commit 13a9ba0750766e5638d8aa2cf27b515533554639 Author: Glauber Ferreira Date: Sat Aug 10 10:51:42 2024 -0300 primeiro commit diff --git a/.hgignore b/.hgignore new file mode 100644 index 0000000..debab32 --- /dev/null +++ b/.hgignore @@ -0,0 +1,29 @@ +syntax: glob + +.svn +bin/baseset/openttd.32.bmp +bin/lang/* +bin/openttd* +bin/*.cfg +bundle/* +bundles/* +config.cache* +config.log +config.pwd +docs/aidocs/* +docs/gamedocs/* +docs/source/* +Makefile +Makefile.am +Makefile.bundle +media/openttd.desktop +media/openttd.desktop.install +objs/* +projects/*.ncb +projects/*.suo +projects/*.sdf +projects/*.opensdf +projects/*.vcproj.*.user +projects/*.vcxproj.user +src/rev.cpp +src/os/windows/ottdres.rc diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..829ec64 --- /dev/null +++ b/COPYING @@ -0,0 +1,343 @@ +This is the license which applies to OpenTTD with the exception of some +3rd party modules. See readme.txt for details + + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000..957ba60 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,236 @@ +# $Id$ + +# This file is part of OpenTTD. +# OpenTTD 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, version 2. +# OpenTTD 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 OpenTTD. If not, see . + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = OpenTTD +OUTPUT_DIRECTORY = docs/source/ +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = ./ +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = YES +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 2 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = YES +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = ./src/ +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.h \ + *.hpp +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = */3rdparty */.svn */script/api +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH =./docs/ +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = YES +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = YES +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = YES +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = ENABLE_NETWORK WITH_ZLIB WITH_LZO WITH_LZMA WITH_SDL WITH_PNG WITH_FONTCONFIG WITH_FREETYPE WITH_ICU UNICODE _UNICODE _GNU_SOURCE FINAL= +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = objs/openttd.tag +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_DEPTH = 1000 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..da66983 --- /dev/null +++ b/Makefile @@ -0,0 +1,188 @@ +# Auto-generated file from 'Makefile.in' -- DO NOT EDIT +# $Id$ + +# This file is part of OpenTTD. +# OpenTTD 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, version 2. +# OpenTTD 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 OpenTTD. If not, see . + +# Check if we want to show what we are doing +ifdef VERBOSE + Q = +else + Q = @ +endif + +include Makefile.am + +CONFIG_CACHE_PWD = config.cache.pwd +CONFIG_CACHE_SOURCE_LIST = config.cache.source.list +BIN_DIR = /home/openttd/openttd-virj-source/bin +ICON_THEME_DIR = /usr/local/share/icons/hicolor +MAN_DIR = /usr/local/share/man/man6 +MENU_DIR = /usr/local/share/applications +SRC_DIR = /home/openttd/openttd-virj-source/src +ROOT_DIR = /home/openttd/openttd-virj-source +BUNDLE_DIR = "$(ROOT_DIR)/bundle" +BUNDLES_DIR = "$(ROOT_DIR)/bundles" +INSTALL_DIR = / +INSTALL_BINARY_DIR = "$(INSTALL_DIR)/"/usr/local/games +INSTALL_MAN_DIR = "$(INSTALL_DIR)/$(MAN_DIR)" +INSTALL_MENU_DIR = "$(INSTALL_DIR)/$(MENU_DIR)" +INSTALL_ICON_DIR = "$(INSTALL_DIR)/"/usr/local/share/pixmaps +INSTALL_ICON_THEME_DIR = "$(INSTALL_DIR)/$(ICON_THEME_DIR)" +INSTALL_DATA_DIR = "$(INSTALL_DIR)/"/usr/local/share/games/openttd +INSTALL_DOC_DIR = "$(INSTALL_DIR)/"/usr/local/share/doc/openttd +SOURCE_LIST = /home/openttd/openttd-virj-source/source.list +CONFIGURE_FILES = /home/openttd/openttd-virj-source/configure /home/openttd/openttd-virj-source/config.lib /home/openttd/openttd-virj-source/Makefile.in /home/openttd/openttd-virj-source/Makefile.grf.in /home/openttd/openttd-virj-source/Makefile.lang.in /home/openttd/openttd-virj-source/Makefile.src.in /home/openttd/openttd-virj-source/Makefile.bundle.in /home/openttd/openttd-virj-source/Makefile.setting.in +BINARY_NAME = openttd +STRIP = strip -s +TTD = openttd +TTDS = $(SRC_DIRS:%=%/$(TTD)) +OS = UNIX +OSXAPP = +LIPO = +AWK = awk +SORT = sort -u +DISTCC = + +RES := $(shell if [ ! -f $(CONFIG_CACHE_PWD) ] || [ "`pwd`" != "`cat $(CONFIG_CACHE_PWD)`" ]; then echo "`pwd`" > $(CONFIG_CACHE_PWD); fi ) +RES := $(shell if [ ! -f $(CONFIG_CACHE_SOURCE_LIST) ] || [ -n "`cmp $(CONFIG_CACHE_SOURCE_LIST) $(SOURCE_LIST) 2>/dev/null`" ]; then cp $(SOURCE_LIST) $(CONFIG_CACHE_SOURCE_LIST); fi ) + +all: config.pwd config.cache +ifdef DISTCC + @if [ -z "`echo '$(MFLAGS)' | grep '\-j'`" ]; then echo; echo "WARNING: you enabled distcc support, but you don't seem to be using the -jN paramter"; echo; fi +endif + @for dir in $(DIRS); do \ + $(MAKE) -C $$dir all || exit 1; \ + done +ifdef LIPO +# Lipo is an OSX thing. If it is defined, it means we are building for universal, +# and so we have have to combine the binaries into one big binary + +# Remove the last binary made by the last compiled target + $(Q)rm -f $(BIN_DIR)/$(TTD) +# Make all the binaries into one + $(Q)$(LIPO) -create -output $(BIN_DIR)/$(TTD) $(TTDS) +endif + +help: + @echo "Available make commands:" + @echo "" + @echo "Compilation:" + @echo " all compile the executable and the lang files" + @echo " lang compile the lang files only" + @echo "Clean up:" + @echo " clean remove the files generated during compilation" + @echo " mrproper remove the files generated during configuration and compilation" + @echo "Run after compilation:" + @echo " run execute openttd after the compilation" + @echo " run-gdb execute openttd in debug mode after the compilation" + @echo " run-prof execute openttd in profiling mode after the compilation" + @echo "Installation:" + @echo " install install the compiled files and the data-files after the compilation" + @echo " bundle create the base for an installation bundle" + @echo " bundle_zip create the zip installation bundle" + @echo " bundle_gzip create the gzip installation bundle" + @echo " bundle_bzip2 create the bzip2 installation bundle" + @echo " bundle_lha create the lha installation bundle" + @echo " bundle_dmg create the dmg installation bundle" + +config.pwd: $(CONFIG_CACHE_PWD) + $(MAKE) reconfigure + +config.cache: $(CONFIG_CACHE_SOURCE_LIST) $(CONFIGURE_FILES) + $(MAKE) reconfigure + +reconfigure: +ifeq ($(shell if test -f config.cache; then echo 1; fi), 1) + @echo "----------------" + @echo "The system detected that source.list or any configure file is altered." + @echo " Going to reconfigure with last known settings..." + @echo "----------------" +# Make sure we don't lock config.cache + @$(shell cat config.cache | sed 's@\\ @\\\\ @g') || exit 1 + @echo "----------------" + @echo "Reconfig done. Please re-execute make." + @echo "----------------" +else + @echo "----------------" + @echo "Have not found a configuration, please run configure first." + @echo "----------------" + @exit 1 +endif + +clean: + @for dir in $(DIRS); do \ + $(MAKE) -C $$dir clean; \ + done + $(Q)rm -rf $(BUNDLE_TARGET) + +lang: + @for dir in $(LANG_DIRS); do \ + $(MAKE) -C $$dir all; \ + done + +mrproper: + @for dir in $(DIRS); do \ + $(MAKE) -C $$dir mrproper; \ + done +# Don't be tempted to merge these two for loops. Doing that breaks make +# --dry-run, since make has this "feature" that it always runs commands +# containing $(MAKE), even when --dry-run is passed. The objective is of +# course to also get a dry-run of submakes, but make is not smart enough +# to see that a for loop runs both a submake and an actual command. + @for dir in $(DIRS); do \ + rm -f $$dir/Makefile; \ + done + $(Q)rm -rf objs + $(Q)rm -f Makefile Makefile.am Makefile.bundle + $(Q)rm -f media/openttd.desktop media/openttd.desktop.install + $(Q)rm -f $(CONFIG_CACHE_SOURCE_LIST) config.cache config.pwd config.log $(CONFIG_CACHE_PWD) +# directories for bundle generation + $(Q)rm -rf $(BUNDLE_DIR) + $(Q)rm -rf $(BUNDLES_DIR) +# output of profiling + $(Q)rm -f $(BIN_DIR)/gmon.out +# output of generating 'API' documentation + $(Q)rm -rf $(ROOT_DIR)/docs/source + $(Q)rm -rf $(ROOT_DIR)/docs/aidocs + $(Q)rm -rf $(ROOT_DIR)/docs/gamedocs +# directories created by OpenTTD on regression testing + $(Q)rm -rf $(BIN_DIR)/ai/regression/content_download $(BIN_DIR)/ai/regression/save $(BIN_DIR)/ai/regression/scenario +distclean: mrproper + +maintainer-clean: distclean + $(Q)rm -f $(BIN_DIR)/baseset/openttd.grf $(BIN_DIR)/baseset/*.obg $(BIN_DIR)/baseset/*.obs $(BIN_DIR)/baseset/*.obm + +depend: + @for dir in $(SRC_DIRS); do \ + $(MAKE) -C $$dir depend; \ + done + +run: all + $(Q)cd /home/openttd/openttd-virj-source/bin && ./openttd $(OPENTTD_ARGS) + +run-gdb: all + $(Q)cd /home/openttd/openttd-virj-source/bin && gdb --ex run --args ./openttd $(OPENTTD_ARGS) + +run-prof: all + $(Q)cd /home/openttd/openttd-virj-source/bin && ./openttd $(OPENTTD_ARGS) && gprof openttd | less + +regression: all + $(Q)cd /home/openttd/openttd-virj-source/bin && sh ai/regression/run.sh +test: regression + +%.o: + @for dir in $(SRC_DIRS); do \ + $(MAKE) -C $$dir $(@:src/%=%); \ + done + +%.lng: + @for dir in $(LANG_DIRS); do \ + $(MAKE) -C $$dir $@; \ + done + +.PHONY: test distclean mrproper clean + +include Makefile.bundle diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..294c5eb --- /dev/null +++ b/Makefile.am @@ -0,0 +1,8 @@ +# Auto-generated file -- DO NOT EDIT + +DIRS += /home/openttd/openttd-virj-source/objs/lang +LANG_DIRS += /home/openttd/openttd-virj-source/objs/lang +DIRS += /home/openttd/openttd-virj-source/objs/setting +DIRS += /home/openttd/openttd-virj-source/objs/extra_grf +DIRS += /home/openttd/openttd-virj-source/objs/release +SRC_DIRS += /home/openttd/openttd-virj-source/objs/release diff --git a/Makefile.bundle b/Makefile.bundle new file mode 100644 index 0000000..969b2eb --- /dev/null +++ b/Makefile.bundle @@ -0,0 +1,229 @@ +# $Id$ + +# This file is part of OpenTTD. +# OpenTTD 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, version 2. +# OpenTTD 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 OpenTTD. If not, see . + +# +# Creation of bundles +# + +# The revision is needed for the bundle name and creating an OSX application bundle. +# Detect the revision +VERSIONS := $(shell AWK="$(AWK)" "$(ROOT_DIR)/findversion.sh") +REV := $(shell echo "$(VERSIONS)" | cut -f 1 -d' ') + +# Make sure we have something in REV +ifeq ($(REV),) +REV := norev000 +endif + +ifndef BUNDLE_NAME +BUNDLE_NAME = openttd-custom-$(REV)-$(OS) +endif + +# An OSX application bundle needs the data files, lang files and openttd executable in a different location. +ifdef OSXAPP +AI_DIR = $(BUNDLE_DIR)/$(OSXAPP)/Contents/Resources/ai +GAME_DIR = $(BUNDLE_DIR)/$(OSXAPP)/Contents/Resources/game +BASESET_DIR = $(BUNDLE_DIR)/$(OSXAPP)/Contents/Resources/baseset +LANG_DIR = $(BUNDLE_DIR)/$(OSXAPP)/Contents/Resources/lang +TTD_DIR = $(BUNDLE_DIR)/$(OSXAPP)/Contents/MacOS +else +AI_DIR = $(BUNDLE_DIR)/ai +GAME_DIR = $(BUNDLE_DIR)/game +BASESET_DIR = $(BUNDLE_DIR)/baseset +LANG_DIR = $(BUNDLE_DIR)/lang +TTD_DIR = $(BUNDLE_DIR) +endif + +bundle: all + @echo '[BUNDLE] Constructing bundle' + $(Q)rm -rf "$(BUNDLE_DIR)" + $(Q)mkdir -p "$(BUNDLE_DIR)" + $(Q)mkdir -p "$(BUNDLE_DIR)/docs" + $(Q)mkdir -p "$(BUNDLE_DIR)/media" + $(Q)mkdir -p "$(BUNDLE_DIR)/scripts" + $(Q)mkdir -p "$(TTD_DIR)" + $(Q)mkdir -p "$(AI_DIR)" + $(Q)mkdir -p "$(GAME_DIR)" + $(Q)mkdir -p "$(BASESET_DIR)" + $(Q)mkdir -p "$(LANG_DIR)" +ifdef OSXAPP + $(Q)mkdir -p "$(BUNDLE_DIR)/$(OSXAPP)/Contents/Resources" + $(Q)echo "APPL????" > "$(BUNDLE_DIR)/$(OSXAPP)/Contents/PkgInfo" + $(Q)cp "$(ROOT_DIR)/os/macosx/openttd.icns" "$(BUNDLE_DIR)/$(OSXAPP)/Contents/Resources/openttd.icns" + $(Q)$(ROOT_DIR)/os/macosx/plistgen.sh "$(BUNDLE_DIR)/$(OSXAPP)" "$(REV)" + $(Q)cp "$(ROOT_DIR)/os/macosx/splash.png" "$(BASESET_DIR)" +endif +ifeq ($(OS),UNIX) + $(Q)cp "$(ROOT_DIR)/media/openttd.32.bmp" "$(BASESET_DIR)/" +endif + $(Q)cp "$(BIN_DIR)/$(TTD)" "$(TTD_DIR)/" + $(Q)cp "$(BIN_DIR)/ai/"compat_*.nut "$(AI_DIR)/" + $(Q)cp "$(BIN_DIR)/game/"compat_*.nut "$(GAME_DIR)/" + $(Q)cp "$(BIN_DIR)/baseset/"*.grf "$(BASESET_DIR)/" + $(Q)cp "$(BIN_DIR)/baseset/"*.obg "$(BASESET_DIR)/" + $(Q)cp "$(BIN_DIR)/baseset/"*.obs "$(BASESET_DIR)/" + $(Q)cp "$(BIN_DIR)/baseset/opntitle.dat" "$(BASESET_DIR)/" + $(Q)cp "$(BIN_DIR)/baseset/"*.obm "$(BASESET_DIR)/" + $(Q)cp "$(BIN_DIR)/lang/"*.lng "$(LANG_DIR)/" + $(Q)cp "$(ROOT_DIR)/readme.txt" "$(BUNDLE_DIR)/" + $(Q)cp "$(ROOT_DIR)/COPYING" "$(BUNDLE_DIR)/" + $(Q)cp "$(ROOT_DIR)/known-bugs.txt" "$(BUNDLE_DIR)/" + $(Q)cp "$(ROOT_DIR)/docs/multiplayer.txt" "$(BUNDLE_DIR)/docs/" + $(Q)cp "$(ROOT_DIR)/changelog.txt" "$(BUNDLE_DIR)/" +ifdef MAN_DIR + $(Q)mkdir -p "$(BUNDLE_DIR)/man/" + $(Q)cp "$(ROOT_DIR)/docs/openttd.6" "$(BUNDLE_DIR)/man/" + $(Q)gzip -9 "$(BUNDLE_DIR)/man/openttd.6" +endif + $(Q)cp "$(ROOT_DIR)/media/openttd.32.xpm" "$(BUNDLE_DIR)/media/" + $(Q)cp "$(ROOT_DIR)/media/openttd."*.png "$(BUNDLE_DIR)/media/" + $(Q)cp "$(BIN_DIR)/scripts/"* "$(BUNDLE_DIR)/scripts/" +ifdef MENU_DIR + $(Q)cp "$(ROOT_DIR)/media/openttd.desktop" "$(BUNDLE_DIR)/media/" + $(Q)$(AWK) -f "$(ROOT_DIR)/media/openttd.desktop.translation.awk" "$(SRC_DIR)/lang/"*.txt | $(SORT) | $(AWK) -f "$(ROOT_DIR)/media/openttd.desktop.filter.awk" >> "$(BUNDLE_DIR)/media/openttd.desktop" + $(Q)sed s/=openttd/=$(BINARY_NAME)/g "$(BUNDLE_DIR)/media/openttd.desktop" > "$(ROOT_DIR)/media/openttd.desktop.install" +endif +ifeq ($(TTD), openttd.exe) + $(Q)unix2dos "$(BUNDLE_DIR)/docs/"* "$(BUNDLE_DIR)/readme.txt" "$(BUNDLE_DIR)/COPYING" "$(BUNDLE_DIR)/changelog.txt" "$(BUNDLE_DIR)/known-bugs.txt" +ifeq ($(OS), DOS) + $(Q)cp "$(ROOT_DIR)/os/dos/cwsdpmi/cwsdpmi.txt" "$(BUNDLE_DIR)/docs/" +ifndef STRIP + $(Q)cp "$(ROOT_DIR)/os/dos/cwsdpmi/cwsdpmi.exe" "$(TTD_DIR)/" +endif +endif +endif + +### Packing the current bundle into several compressed file formats ### +# +# Zips & dmgs do not contain a root folder, i.e. they have files in the root of the zip/dmg. +# gzip, bzip2 and lha archives have a root folder, with the same name as the bundle. +# +# One can supply a custom name by adding BUNDLE_NAME:= to the make command. +# +bundle_zip: bundle + @echo '[BUNDLE] Creating $(BUNDLE_NAME).zip' + $(Q)mkdir -p "$(BUNDLES_DIR)" + $(Q)cd "$(BUNDLE_DIR)" && zip -r $(shell if test -z "$(VERBOSE)"; then echo '-q'; fi) "$(BUNDLES_DIR)/$(BUNDLE_NAME).zip" . + +bundle_7z: bundle + @echo '[BUNDLE] Creating $(BUNDLE_NAME).7z' + $(Q)mkdir -p "$(BUNDLES_DIR)" + $(Q)cd "$(BUNDLE_DIR)" && 7z a "$(BUNDLES_DIR)/$(BUNDLE_NAME).7z" . + +bundle_gzip: bundle + @echo '[BUNDLE] Creating $(BUNDLE_NAME).tar.gz' + $(Q)mkdir -p "$(BUNDLES_DIR)/.gzip/$(BUNDLE_NAME)" + $(Q)cp -R "$(BUNDLE_DIR)/"* "$(BUNDLES_DIR)/.gzip/$(BUNDLE_NAME)/" + $(Q)cd "$(BUNDLES_DIR)/.gzip" && tar -zc$(shell if test -n "$(VERBOSE)"; then echo 'v'; fi)f "$(BUNDLES_DIR)/$(BUNDLE_NAME).tar.gz" "$(BUNDLE_NAME)" + $(Q)rm -rf "$(BUNDLES_DIR)/.gzip" + +bundle_bzip2: bundle + @echo '[BUNDLE] Creating $(BUNDLE_NAME).tar.bz2' + $(Q)mkdir -p "$(BUNDLES_DIR)/.bzip2/$(BUNDLE_NAME)" + $(Q)cp -R "$(BUNDLE_DIR)/"* "$(BUNDLES_DIR)/.bzip2/$(BUNDLE_NAME)/" + $(Q)cd "$(BUNDLES_DIR)/.bzip2" && tar -jc$(shell if test -n "$(VERBOSE)"; then echo 'v'; fi)f "$(BUNDLES_DIR)/$(BUNDLE_NAME).tar.bz2" "$(BUNDLE_NAME)" + $(Q)rm -rf "$(BUNDLES_DIR)/.bzip2" + +bundle_lzma: bundle + @echo '[BUNDLE] Creating $(BUNDLE_NAME).tar.lzma' + $(Q)mkdir -p "$(BUNDLES_DIR)/.lzma/$(BUNDLE_NAME)" + $(Q)cp -R "$(BUNDLE_DIR)/"* "$(BUNDLES_DIR)/.lzma/$(BUNDLE_NAME)/" + $(Q)cd "$(BUNDLES_DIR)/.lzma" && tar --lzma -c$(shell if test -n "$(VERBOSE)"; then echo 'v'; fi)f "$(BUNDLES_DIR)/$(BUNDLE_NAME).tar.lzma" "$(BUNDLE_NAME)" + $(Q)rm -rf "$(BUNDLES_DIR)/.lzma" + +bundle_xz: bundle + @echo '[BUNDLE] Creating $(BUNDLE_NAME).tar.xz' + $(Q)mkdir -p "$(BUNDLES_DIR)/.xz/$(BUNDLE_NAME)" + $(Q)cp -R "$(BUNDLE_DIR)/"* "$(BUNDLES_DIR)/.xz/$(BUNDLE_NAME)/" + $(Q)cd "$(BUNDLES_DIR)/.xz" && tar --xz -c$(shell if test -n "$(VERBOSE)"; then echo 'v'; fi)f "$(BUNDLES_DIR)/$(BUNDLE_NAME).tar.xz" "$(BUNDLE_NAME)" + $(Q)rm -rf "$(BUNDLES_DIR)/.xz" + +bundle_lha: bundle + @echo '[BUNDLE] Creating $(BUNDLE_NAME).lha' + $(Q)mkdir -p "$(BUNDLES_DIR)/.lha/$(BUNDLE_NAME)" + $(Q)cp -R "$(BUNDLE_DIR)/"* "$(BUNDLES_DIR)/.lha/$(BUNDLE_NAME)/" + $(Q)cd "$(BUNDLES_DIR)/.lha" && lha ao6 "$(BUNDLES_DIR)/$(BUNDLE_NAME).lha" "$(BUNDLE_NAME)" + $(Q)rm -rf "$(BUNDLES_DIR)/.lha" + +bundle_dmg: bundle + @echo '[BUNDLE] Creating $(BUNDLE_NAME).dmg' + $(Q)mkdir -p "$(BUNDLES_DIR)/OpenTTD $(REV)" + $(Q)cp -R "$(BUNDLE_DIR)/" "$(BUNDLES_DIR)/OpenTTD $(REV)" + $(Q)hdiutil create -ov -format UDZO -srcfolder "$(BUNDLES_DIR)/OpenTTD $(REV)" "$(BUNDLES_DIR)/$(BUNDLE_NAME).dmg" + $(Q)rm -fr "$(BUNDLES_DIR)/OpenTTD $(REV)" + +bundle_exe: all + @echo '[BUNDLE] Creating $(BUNDLE_NAME).exe' + $(Q)mkdir -p "$(BUNDLES_DIR)" + $(Q)unix2dos "$(ROOT_DIR)/docs/"*.txt "$(ROOT_DIR)/readme.txt" "$(ROOT_DIR)/COPYING" "$(ROOT_DIR)/changelog.txt" "$(ROOT_DIR)/known-bugs.txt" + $(Q)cd $(ROOT_DIR)/os/windows/installer && makensis.exe //DVERSION_INCLUDE=version_$(PLATFORM).txt install.nsi + $(Q)mv $(ROOT_DIR)/os/windows/installer/*$(PLATFORM).exe "$(BUNDLES_DIR)/$(BUNDLE_NAME).exe" + +ifdef OSXAPP +install: + @echo '[INSTALL] Cannot install the OSX Application Bundle' +else +install: bundle + @echo '[INSTALL] Installing OpenTTD' + $(Q)install -d "$(INSTALL_BINARY_DIR)" + $(Q)install -d "$(INSTALL_ICON_DIR)" + $(Q)install -d "$(INSTALL_DATA_DIR)/ai" + $(Q)install -d "$(INSTALL_DATA_DIR)/game" + $(Q)install -d "$(INSTALL_DATA_DIR)/baseset" + $(Q)install -d "$(INSTALL_DATA_DIR)/lang" + $(Q)install -d "$(INSTALL_DATA_DIR)/scripts" +ifeq ($(TTD), openttd.exe) + $(Q)install -m 755 "$(BUNDLE_DIR)/$(TTD)" "$(INSTALL_BINARY_DIR)/${BINARY_NAME}.exe" +else + $(Q)install -m 755 "$(BUNDLE_DIR)/$(TTD)" "$(INSTALL_BINARY_DIR)/${BINARY_NAME}" +endif + $(Q)install -m 644 "$(BUNDLE_DIR)/lang/"* "$(INSTALL_DATA_DIR)/lang" + $(Q)install -m 644 "$(BUNDLE_DIR)/ai/"* "$(INSTALL_DATA_DIR)/ai" + $(Q)install -m 644 "$(BUNDLE_DIR)/game/"* "$(INSTALL_DATA_DIR)/game" + $(Q)install -m 644 "$(BUNDLE_DIR)/baseset/"* "$(INSTALL_DATA_DIR)/baseset" + $(Q)install -m 644 "$(BUNDLE_DIR)/scripts/"* "$(INSTALL_DATA_DIR)/scripts" +ifndef DO_NOT_INSTALL_DOCS + $(Q)install -d "$(INSTALL_DOC_DIR)" + $(Q)install -m 644 "$(BUNDLE_DIR)/docs/"* "$(BUNDLE_DIR)/readme.txt" "$(BUNDLE_DIR)/known-bugs.txt" "$(INSTALL_DOC_DIR)" +endif +ifndef DO_NOT_INSTALL_CHANGELOG + $(Q)install -d "$(INSTALL_DOC_DIR)" + $(Q)install -m 644 "$(BUNDLE_DIR)/changelog.txt" "$(INSTALL_DOC_DIR)" +endif +ifndef DO_NOT_INSTALL_LICENSE + $(Q)install -d "$(INSTALL_DOC_DIR)" + $(Q)install -m 644 "$(BUNDLE_DIR)/COPYING" "$(INSTALL_DOC_DIR)" +endif + $(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.32.xpm" "$(INSTALL_ICON_DIR)/${BINARY_NAME}.32.xpm" +ifdef ICON_THEME_DIR + $(Q)install -d "$(INSTALL_ICON_THEME_DIR)" + $(Q)install -d "$(INSTALL_ICON_THEME_DIR)/16x16/apps" + $(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.16.png" "$(INSTALL_ICON_THEME_DIR)/16x16/apps/${BINARY_NAME}.png" + $(Q)install -d "$(INSTALL_ICON_THEME_DIR)/32x32/apps" + $(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.32.png" "$(INSTALL_ICON_THEME_DIR)/32x32/apps/${BINARY_NAME}.png" + $(Q)install -d "$(INSTALL_ICON_THEME_DIR)/48x48/apps" + $(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.48.png" "$(INSTALL_ICON_THEME_DIR)/48x48/apps/${BINARY_NAME}.png" + $(Q)install -d "$(INSTALL_ICON_THEME_DIR)/64x64/apps" + $(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.64.png" "$(INSTALL_ICON_THEME_DIR)/64x64/apps/${BINARY_NAME}.png" + $(Q)install -d "$(INSTALL_ICON_THEME_DIR)/128x128/apps" + $(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.128.png" "$(INSTALL_ICON_THEME_DIR)/128x128/apps/${BINARY_NAME}.png" + $(Q)install -d "$(INSTALL_ICON_THEME_DIR)/256x256/apps" + $(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.256.png" "$(INSTALL_ICON_THEME_DIR)/256x256/apps/${BINARY_NAME}.png" +else + $(Q)install -m 644 "$(BUNDLE_DIR)/media/"*.png "$(INSTALL_ICON_DIR)" +endif +ifdef MAN_DIR +ifndef DO_NOT_INSTALL_MAN + $(Q)install -d "$(INSTALL_MAN_DIR)" + $(Q)install -m 644 "$(BUNDLE_DIR)/man/openttd.6.gz" "$(INSTALL_MAN_DIR)/${BINARY_NAME}.6.gz" +endif +endif +ifdef MENU_DIR + $(Q)install -d "$(INSTALL_MENU_DIR)" + $(Q)install -m 644 "$(ROOT_DIR)/media/openttd.desktop.install" "$(INSTALL_MENU_DIR)/${BINARY_NAME}.desktop" +endif +endif # OSXAPP diff --git a/Makefile.bundle.in b/Makefile.bundle.in new file mode 100644 index 0000000..969b2eb --- /dev/null +++ b/Makefile.bundle.in @@ -0,0 +1,229 @@ +# $Id$ + +# This file is part of OpenTTD. +# OpenTTD 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, version 2. +# OpenTTD 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 OpenTTD. If not, see . + +# +# Creation of bundles +# + +# The revision is needed for the bundle name and creating an OSX application bundle. +# Detect the revision +VERSIONS := $(shell AWK="$(AWK)" "$(ROOT_DIR)/findversion.sh") +REV := $(shell echo "$(VERSIONS)" | cut -f 1 -d' ') + +# Make sure we have something in REV +ifeq ($(REV),) +REV := norev000 +endif + +ifndef BUNDLE_NAME +BUNDLE_NAME = openttd-custom-$(REV)-$(OS) +endif + +# An OSX application bundle needs the data files, lang files and openttd executable in a different location. +ifdef OSXAPP +AI_DIR = $(BUNDLE_DIR)/$(OSXAPP)/Contents/Resources/ai +GAME_DIR = $(BUNDLE_DIR)/$(OSXAPP)/Contents/Resources/game +BASESET_DIR = $(BUNDLE_DIR)/$(OSXAPP)/Contents/Resources/baseset +LANG_DIR = $(BUNDLE_DIR)/$(OSXAPP)/Contents/Resources/lang +TTD_DIR = $(BUNDLE_DIR)/$(OSXAPP)/Contents/MacOS +else +AI_DIR = $(BUNDLE_DIR)/ai +GAME_DIR = $(BUNDLE_DIR)/game +BASESET_DIR = $(BUNDLE_DIR)/baseset +LANG_DIR = $(BUNDLE_DIR)/lang +TTD_DIR = $(BUNDLE_DIR) +endif + +bundle: all + @echo '[BUNDLE] Constructing bundle' + $(Q)rm -rf "$(BUNDLE_DIR)" + $(Q)mkdir -p "$(BUNDLE_DIR)" + $(Q)mkdir -p "$(BUNDLE_DIR)/docs" + $(Q)mkdir -p "$(BUNDLE_DIR)/media" + $(Q)mkdir -p "$(BUNDLE_DIR)/scripts" + $(Q)mkdir -p "$(TTD_DIR)" + $(Q)mkdir -p "$(AI_DIR)" + $(Q)mkdir -p "$(GAME_DIR)" + $(Q)mkdir -p "$(BASESET_DIR)" + $(Q)mkdir -p "$(LANG_DIR)" +ifdef OSXAPP + $(Q)mkdir -p "$(BUNDLE_DIR)/$(OSXAPP)/Contents/Resources" + $(Q)echo "APPL????" > "$(BUNDLE_DIR)/$(OSXAPP)/Contents/PkgInfo" + $(Q)cp "$(ROOT_DIR)/os/macosx/openttd.icns" "$(BUNDLE_DIR)/$(OSXAPP)/Contents/Resources/openttd.icns" + $(Q)$(ROOT_DIR)/os/macosx/plistgen.sh "$(BUNDLE_DIR)/$(OSXAPP)" "$(REV)" + $(Q)cp "$(ROOT_DIR)/os/macosx/splash.png" "$(BASESET_DIR)" +endif +ifeq ($(OS),UNIX) + $(Q)cp "$(ROOT_DIR)/media/openttd.32.bmp" "$(BASESET_DIR)/" +endif + $(Q)cp "$(BIN_DIR)/$(TTD)" "$(TTD_DIR)/" + $(Q)cp "$(BIN_DIR)/ai/"compat_*.nut "$(AI_DIR)/" + $(Q)cp "$(BIN_DIR)/game/"compat_*.nut "$(GAME_DIR)/" + $(Q)cp "$(BIN_DIR)/baseset/"*.grf "$(BASESET_DIR)/" + $(Q)cp "$(BIN_DIR)/baseset/"*.obg "$(BASESET_DIR)/" + $(Q)cp "$(BIN_DIR)/baseset/"*.obs "$(BASESET_DIR)/" + $(Q)cp "$(BIN_DIR)/baseset/opntitle.dat" "$(BASESET_DIR)/" + $(Q)cp "$(BIN_DIR)/baseset/"*.obm "$(BASESET_DIR)/" + $(Q)cp "$(BIN_DIR)/lang/"*.lng "$(LANG_DIR)/" + $(Q)cp "$(ROOT_DIR)/readme.txt" "$(BUNDLE_DIR)/" + $(Q)cp "$(ROOT_DIR)/COPYING" "$(BUNDLE_DIR)/" + $(Q)cp "$(ROOT_DIR)/known-bugs.txt" "$(BUNDLE_DIR)/" + $(Q)cp "$(ROOT_DIR)/docs/multiplayer.txt" "$(BUNDLE_DIR)/docs/" + $(Q)cp "$(ROOT_DIR)/changelog.txt" "$(BUNDLE_DIR)/" +ifdef MAN_DIR + $(Q)mkdir -p "$(BUNDLE_DIR)/man/" + $(Q)cp "$(ROOT_DIR)/docs/openttd.6" "$(BUNDLE_DIR)/man/" + $(Q)gzip -9 "$(BUNDLE_DIR)/man/openttd.6" +endif + $(Q)cp "$(ROOT_DIR)/media/openttd.32.xpm" "$(BUNDLE_DIR)/media/" + $(Q)cp "$(ROOT_DIR)/media/openttd."*.png "$(BUNDLE_DIR)/media/" + $(Q)cp "$(BIN_DIR)/scripts/"* "$(BUNDLE_DIR)/scripts/" +ifdef MENU_DIR + $(Q)cp "$(ROOT_DIR)/media/openttd.desktop" "$(BUNDLE_DIR)/media/" + $(Q)$(AWK) -f "$(ROOT_DIR)/media/openttd.desktop.translation.awk" "$(SRC_DIR)/lang/"*.txt | $(SORT) | $(AWK) -f "$(ROOT_DIR)/media/openttd.desktop.filter.awk" >> "$(BUNDLE_DIR)/media/openttd.desktop" + $(Q)sed s/=openttd/=$(BINARY_NAME)/g "$(BUNDLE_DIR)/media/openttd.desktop" > "$(ROOT_DIR)/media/openttd.desktop.install" +endif +ifeq ($(TTD), openttd.exe) + $(Q)unix2dos "$(BUNDLE_DIR)/docs/"* "$(BUNDLE_DIR)/readme.txt" "$(BUNDLE_DIR)/COPYING" "$(BUNDLE_DIR)/changelog.txt" "$(BUNDLE_DIR)/known-bugs.txt" +ifeq ($(OS), DOS) + $(Q)cp "$(ROOT_DIR)/os/dos/cwsdpmi/cwsdpmi.txt" "$(BUNDLE_DIR)/docs/" +ifndef STRIP + $(Q)cp "$(ROOT_DIR)/os/dos/cwsdpmi/cwsdpmi.exe" "$(TTD_DIR)/" +endif +endif +endif + +### Packing the current bundle into several compressed file formats ### +# +# Zips & dmgs do not contain a root folder, i.e. they have files in the root of the zip/dmg. +# gzip, bzip2 and lha archives have a root folder, with the same name as the bundle. +# +# One can supply a custom name by adding BUNDLE_NAME:= to the make command. +# +bundle_zip: bundle + @echo '[BUNDLE] Creating $(BUNDLE_NAME).zip' + $(Q)mkdir -p "$(BUNDLES_DIR)" + $(Q)cd "$(BUNDLE_DIR)" && zip -r $(shell if test -z "$(VERBOSE)"; then echo '-q'; fi) "$(BUNDLES_DIR)/$(BUNDLE_NAME).zip" . + +bundle_7z: bundle + @echo '[BUNDLE] Creating $(BUNDLE_NAME).7z' + $(Q)mkdir -p "$(BUNDLES_DIR)" + $(Q)cd "$(BUNDLE_DIR)" && 7z a "$(BUNDLES_DIR)/$(BUNDLE_NAME).7z" . + +bundle_gzip: bundle + @echo '[BUNDLE] Creating $(BUNDLE_NAME).tar.gz' + $(Q)mkdir -p "$(BUNDLES_DIR)/.gzip/$(BUNDLE_NAME)" + $(Q)cp -R "$(BUNDLE_DIR)/"* "$(BUNDLES_DIR)/.gzip/$(BUNDLE_NAME)/" + $(Q)cd "$(BUNDLES_DIR)/.gzip" && tar -zc$(shell if test -n "$(VERBOSE)"; then echo 'v'; fi)f "$(BUNDLES_DIR)/$(BUNDLE_NAME).tar.gz" "$(BUNDLE_NAME)" + $(Q)rm -rf "$(BUNDLES_DIR)/.gzip" + +bundle_bzip2: bundle + @echo '[BUNDLE] Creating $(BUNDLE_NAME).tar.bz2' + $(Q)mkdir -p "$(BUNDLES_DIR)/.bzip2/$(BUNDLE_NAME)" + $(Q)cp -R "$(BUNDLE_DIR)/"* "$(BUNDLES_DIR)/.bzip2/$(BUNDLE_NAME)/" + $(Q)cd "$(BUNDLES_DIR)/.bzip2" && tar -jc$(shell if test -n "$(VERBOSE)"; then echo 'v'; fi)f "$(BUNDLES_DIR)/$(BUNDLE_NAME).tar.bz2" "$(BUNDLE_NAME)" + $(Q)rm -rf "$(BUNDLES_DIR)/.bzip2" + +bundle_lzma: bundle + @echo '[BUNDLE] Creating $(BUNDLE_NAME).tar.lzma' + $(Q)mkdir -p "$(BUNDLES_DIR)/.lzma/$(BUNDLE_NAME)" + $(Q)cp -R "$(BUNDLE_DIR)/"* "$(BUNDLES_DIR)/.lzma/$(BUNDLE_NAME)/" + $(Q)cd "$(BUNDLES_DIR)/.lzma" && tar --lzma -c$(shell if test -n "$(VERBOSE)"; then echo 'v'; fi)f "$(BUNDLES_DIR)/$(BUNDLE_NAME).tar.lzma" "$(BUNDLE_NAME)" + $(Q)rm -rf "$(BUNDLES_DIR)/.lzma" + +bundle_xz: bundle + @echo '[BUNDLE] Creating $(BUNDLE_NAME).tar.xz' + $(Q)mkdir -p "$(BUNDLES_DIR)/.xz/$(BUNDLE_NAME)" + $(Q)cp -R "$(BUNDLE_DIR)/"* "$(BUNDLES_DIR)/.xz/$(BUNDLE_NAME)/" + $(Q)cd "$(BUNDLES_DIR)/.xz" && tar --xz -c$(shell if test -n "$(VERBOSE)"; then echo 'v'; fi)f "$(BUNDLES_DIR)/$(BUNDLE_NAME).tar.xz" "$(BUNDLE_NAME)" + $(Q)rm -rf "$(BUNDLES_DIR)/.xz" + +bundle_lha: bundle + @echo '[BUNDLE] Creating $(BUNDLE_NAME).lha' + $(Q)mkdir -p "$(BUNDLES_DIR)/.lha/$(BUNDLE_NAME)" + $(Q)cp -R "$(BUNDLE_DIR)/"* "$(BUNDLES_DIR)/.lha/$(BUNDLE_NAME)/" + $(Q)cd "$(BUNDLES_DIR)/.lha" && lha ao6 "$(BUNDLES_DIR)/$(BUNDLE_NAME).lha" "$(BUNDLE_NAME)" + $(Q)rm -rf "$(BUNDLES_DIR)/.lha" + +bundle_dmg: bundle + @echo '[BUNDLE] Creating $(BUNDLE_NAME).dmg' + $(Q)mkdir -p "$(BUNDLES_DIR)/OpenTTD $(REV)" + $(Q)cp -R "$(BUNDLE_DIR)/" "$(BUNDLES_DIR)/OpenTTD $(REV)" + $(Q)hdiutil create -ov -format UDZO -srcfolder "$(BUNDLES_DIR)/OpenTTD $(REV)" "$(BUNDLES_DIR)/$(BUNDLE_NAME).dmg" + $(Q)rm -fr "$(BUNDLES_DIR)/OpenTTD $(REV)" + +bundle_exe: all + @echo '[BUNDLE] Creating $(BUNDLE_NAME).exe' + $(Q)mkdir -p "$(BUNDLES_DIR)" + $(Q)unix2dos "$(ROOT_DIR)/docs/"*.txt "$(ROOT_DIR)/readme.txt" "$(ROOT_DIR)/COPYING" "$(ROOT_DIR)/changelog.txt" "$(ROOT_DIR)/known-bugs.txt" + $(Q)cd $(ROOT_DIR)/os/windows/installer && makensis.exe //DVERSION_INCLUDE=version_$(PLATFORM).txt install.nsi + $(Q)mv $(ROOT_DIR)/os/windows/installer/*$(PLATFORM).exe "$(BUNDLES_DIR)/$(BUNDLE_NAME).exe" + +ifdef OSXAPP +install: + @echo '[INSTALL] Cannot install the OSX Application Bundle' +else +install: bundle + @echo '[INSTALL] Installing OpenTTD' + $(Q)install -d "$(INSTALL_BINARY_DIR)" + $(Q)install -d "$(INSTALL_ICON_DIR)" + $(Q)install -d "$(INSTALL_DATA_DIR)/ai" + $(Q)install -d "$(INSTALL_DATA_DIR)/game" + $(Q)install -d "$(INSTALL_DATA_DIR)/baseset" + $(Q)install -d "$(INSTALL_DATA_DIR)/lang" + $(Q)install -d "$(INSTALL_DATA_DIR)/scripts" +ifeq ($(TTD), openttd.exe) + $(Q)install -m 755 "$(BUNDLE_DIR)/$(TTD)" "$(INSTALL_BINARY_DIR)/${BINARY_NAME}.exe" +else + $(Q)install -m 755 "$(BUNDLE_DIR)/$(TTD)" "$(INSTALL_BINARY_DIR)/${BINARY_NAME}" +endif + $(Q)install -m 644 "$(BUNDLE_DIR)/lang/"* "$(INSTALL_DATA_DIR)/lang" + $(Q)install -m 644 "$(BUNDLE_DIR)/ai/"* "$(INSTALL_DATA_DIR)/ai" + $(Q)install -m 644 "$(BUNDLE_DIR)/game/"* "$(INSTALL_DATA_DIR)/game" + $(Q)install -m 644 "$(BUNDLE_DIR)/baseset/"* "$(INSTALL_DATA_DIR)/baseset" + $(Q)install -m 644 "$(BUNDLE_DIR)/scripts/"* "$(INSTALL_DATA_DIR)/scripts" +ifndef DO_NOT_INSTALL_DOCS + $(Q)install -d "$(INSTALL_DOC_DIR)" + $(Q)install -m 644 "$(BUNDLE_DIR)/docs/"* "$(BUNDLE_DIR)/readme.txt" "$(BUNDLE_DIR)/known-bugs.txt" "$(INSTALL_DOC_DIR)" +endif +ifndef DO_NOT_INSTALL_CHANGELOG + $(Q)install -d "$(INSTALL_DOC_DIR)" + $(Q)install -m 644 "$(BUNDLE_DIR)/changelog.txt" "$(INSTALL_DOC_DIR)" +endif +ifndef DO_NOT_INSTALL_LICENSE + $(Q)install -d "$(INSTALL_DOC_DIR)" + $(Q)install -m 644 "$(BUNDLE_DIR)/COPYING" "$(INSTALL_DOC_DIR)" +endif + $(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.32.xpm" "$(INSTALL_ICON_DIR)/${BINARY_NAME}.32.xpm" +ifdef ICON_THEME_DIR + $(Q)install -d "$(INSTALL_ICON_THEME_DIR)" + $(Q)install -d "$(INSTALL_ICON_THEME_DIR)/16x16/apps" + $(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.16.png" "$(INSTALL_ICON_THEME_DIR)/16x16/apps/${BINARY_NAME}.png" + $(Q)install -d "$(INSTALL_ICON_THEME_DIR)/32x32/apps" + $(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.32.png" "$(INSTALL_ICON_THEME_DIR)/32x32/apps/${BINARY_NAME}.png" + $(Q)install -d "$(INSTALL_ICON_THEME_DIR)/48x48/apps" + $(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.48.png" "$(INSTALL_ICON_THEME_DIR)/48x48/apps/${BINARY_NAME}.png" + $(Q)install -d "$(INSTALL_ICON_THEME_DIR)/64x64/apps" + $(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.64.png" "$(INSTALL_ICON_THEME_DIR)/64x64/apps/${BINARY_NAME}.png" + $(Q)install -d "$(INSTALL_ICON_THEME_DIR)/128x128/apps" + $(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.128.png" "$(INSTALL_ICON_THEME_DIR)/128x128/apps/${BINARY_NAME}.png" + $(Q)install -d "$(INSTALL_ICON_THEME_DIR)/256x256/apps" + $(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.256.png" "$(INSTALL_ICON_THEME_DIR)/256x256/apps/${BINARY_NAME}.png" +else + $(Q)install -m 644 "$(BUNDLE_DIR)/media/"*.png "$(INSTALL_ICON_DIR)" +endif +ifdef MAN_DIR +ifndef DO_NOT_INSTALL_MAN + $(Q)install -d "$(INSTALL_MAN_DIR)" + $(Q)install -m 644 "$(BUNDLE_DIR)/man/openttd.6.gz" "$(INSTALL_MAN_DIR)/${BINARY_NAME}.6.gz" +endif +endif +ifdef MENU_DIR + $(Q)install -d "$(INSTALL_MENU_DIR)" + $(Q)install -m 644 "$(ROOT_DIR)/media/openttd.desktop.install" "$(INSTALL_MENU_DIR)/${BINARY_NAME}.desktop" +endif +endif # OSXAPP diff --git a/Makefile.grf.in b/Makefile.grf.in new file mode 100644 index 0000000..c2d058d --- /dev/null +++ b/Makefile.grf.in @@ -0,0 +1,95 @@ +# $Id$ + +# This file is part of OpenTTD. +# OpenTTD 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, version 2. +# OpenTTD 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 OpenTTD. If not, see . +# +# Building requires GRFCodec and NFORenum. Older versions of GRFCodec are +# known to miscompile the graphics. +# +# Recent nightlies (including sources) of both can be found at: +# http://www.openttd.org/download-grfcodec +# http://www.openttd.org/download-nforenum +# +# The mercurial repository of both can be found at: +# http://hg.openttdcoop.org/grfcodec +# http://hg.openttdcoop.org/nforenum +# + + +ROOT_DIR = !!ROOT_DIR!! +GRF_DIR = $(ROOT_DIR)/media/extra_grf +BASESET_DIR = $(ROOT_DIR)/media/baseset +LANG_DIR = $(ROOT_DIR)/src/lang +BIN_DIR = !!BIN_DIR!!/baseset +OBJS_DIR = !!GRF_OBJS_DIR!! +OS = !!OS!! +STAGE = !!STAGE!! + +# Check if we want to show what we are doing +ifdef VERBOSE + Q = + E = @true +else + Q = @ + E = @echo +endif + +GRFCODEC := !!GRFCODEC!! +NFORENUM := !!NFORENUM!! +CC_BUILD := !!CC_BUILD!! +MD5SUM := $(shell [ "$(OS)" = "OSX" ] && echo "md5 -r" || echo "md5sum") + +# Some "should not be changed" settings. +NFO_FILES := $(GRF_DIR)/*.nfo $(GRF_DIR)/rivers/*.nfo +PNG_FILES := $(GRF_DIR)/*.png $(GRF_DIR)/rivers/*.png + +# Build the GRF. +ifdef GRFCODEC +all: $(BIN_DIR)/openttd.grf $(BIN_DIR)/orig_dos.obg $(BIN_DIR)/orig_dos_de.obg $(BIN_DIR)/orig_win.obg $(BIN_DIR)/orig_dos.obs $(BIN_DIR)/orig_win.obs $(BIN_DIR)/no_sound.obs $(BIN_DIR)/orig_win.obm $(BIN_DIR)/no_music.obm +else +all: +endif + +# Make sure the sprites directory exists. +$(OBJS_DIR)/sprites: + $(Q)-mkdir "$@" + +$(OBJS_DIR)/langfiles.tmp: $(LANG_DIR)/*.txt + $(E) '$(STAGE) Collecting baseset translations' + $(Q) cat $^ > $@ + +$(BIN_DIR)/%.obg: $(BASESET_DIR)/%.obg $(BIN_DIR)/openttd.grf $(OBJS_DIR)/langfiles.tmp $(BASESET_DIR)/translations.awk + $(E) '$(STAGE) Updating $(notdir $@)' + $(Q) sed 's/^OPENTTD.GRF = *[0-9a-f]*$$/OPENTTD.GRF = '`$(MD5SUM) $(BIN_DIR)/openttd.grf | sed 's@ .*@@'`'/' $< > $@.tmp + $(Q) awk -v langfiles='$(OBJS_DIR)/langfiles.tmp' -f $(BASESET_DIR)/translations.awk $@.tmp >$@ + $(Q) rm $@.tmp + +$(BIN_DIR)/%.obs: $(BASESET_DIR)/%.obs $(OBJS_DIR)/langfiles.tmp $(BASESET_DIR)/translations.awk + $(E) '$(STAGE) Updating $(notdir $@)' + $(Q) awk -v langfiles='$(OBJS_DIR)/langfiles.tmp' -f $(BASESET_DIR)/translations.awk $< >$@ + +$(BIN_DIR)/%.obm: $(BASESET_DIR)/%.obm $(OBJS_DIR)/langfiles.tmp $(BASESET_DIR)/translations.awk + $(E) '$(STAGE) Updating $(notdir $@)' + $(Q) awk -v langfiles='$(OBJS_DIR)/langfiles.tmp' -f $(BASESET_DIR)/translations.awk $< >$@ + +# Compile extra grf +$(BIN_DIR)/openttd.grf: $(PNG_FILES) $(NFO_FILES) $(OBJS_DIR)/sprites $(GRF_DIR)/assemble_nfo.awk + $(E) '$(STAGE) Assembling openttd.nfo' + $(Q)-cp $(PNG_FILES) $(OBJS_DIR)/sprites 2> /dev/null + $(Q) awk -f $(GRF_DIR)/assemble_nfo.awk $(GRF_DIR)/openttd.nfo > $(OBJS_DIR)/sprites/openttd.nfo + $(Q) $(NFORENUM) -s $(OBJS_DIR)/sprites/openttd.nfo + $(E) '$(STAGE) Compiling openttd.grf' + $(Q) $(GRFCODEC) -n -s -e -p1 $(OBJS_DIR)/openttd.grf + $(Q)cp $(OBJS_DIR)/openttd.grf $(BIN_DIR)/openttd.grf + +# Clean up temporary files. +clean: + $(Q)rm -f *.bak *.grf + +# Clean up temporary files +mrproper: clean + $(Q)rm -fr sprites + +.PHONY: all mrproper depend clean diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..0d50fc1 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,187 @@ +# $Id$ + +# This file is part of OpenTTD. +# OpenTTD 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, version 2. +# OpenTTD 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 OpenTTD. If not, see . + +# Check if we want to show what we are doing +ifdef VERBOSE + Q = +else + Q = @ +endif + +include Makefile.am + +CONFIG_CACHE_PWD = !!CONFIG_CACHE_PWD!! +CONFIG_CACHE_SOURCE_LIST = !!CONFIG_CACHE_SOURCE_LIST!! +BIN_DIR = !!BIN_DIR!! +ICON_THEME_DIR = !!ICON_THEME_DIR!! +MAN_DIR = !!MAN_DIR!! +MENU_DIR = !!MENU_DIR!! +SRC_DIR = !!SRC_DIR!! +ROOT_DIR = !!ROOT_DIR!! +BUNDLE_DIR = "$(ROOT_DIR)/bundle" +BUNDLES_DIR = "$(ROOT_DIR)/bundles" +INSTALL_DIR = !!INSTALL_DIR!! +INSTALL_BINARY_DIR = "$(INSTALL_DIR)/"!!BINARY_DIR!! +INSTALL_MAN_DIR = "$(INSTALL_DIR)/$(MAN_DIR)" +INSTALL_MENU_DIR = "$(INSTALL_DIR)/$(MENU_DIR)" +INSTALL_ICON_DIR = "$(INSTALL_DIR)/"!!ICON_DIR!! +INSTALL_ICON_THEME_DIR = "$(INSTALL_DIR)/$(ICON_THEME_DIR)" +INSTALL_DATA_DIR = "$(INSTALL_DIR)/"!!DATA_DIR!! +INSTALL_DOC_DIR = "$(INSTALL_DIR)/"!!DOC_DIR!! +SOURCE_LIST = !!SOURCE_LIST!! +CONFIGURE_FILES = !!CONFIGURE_FILES!! +BINARY_NAME = !!BINARY_NAME!! +STRIP = !!STRIP!! +TTD = !!TTD!! +TTDS = $(SRC_DIRS:%=%/$(TTD)) +OS = !!OS!! +OSXAPP = !!OSXAPP!! +LIPO = !!LIPO!! +AWK = !!AWK!! +SORT = !!SORT!! +DISTCC = !!DISTCC!! + +RES := $(shell if [ ! -f $(CONFIG_CACHE_PWD) ] || [ "`pwd`" != "`cat $(CONFIG_CACHE_PWD)`" ]; then echo "`pwd`" > $(CONFIG_CACHE_PWD); fi ) +RES := $(shell if [ ! -f $(CONFIG_CACHE_SOURCE_LIST) ] || [ -n "`cmp $(CONFIG_CACHE_SOURCE_LIST) $(SOURCE_LIST) 2>/dev/null`" ]; then cp $(SOURCE_LIST) $(CONFIG_CACHE_SOURCE_LIST); fi ) + +all: config.pwd config.cache +ifdef DISTCC + @if [ -z "`echo '$(MFLAGS)' | grep '\-j'`" ]; then echo; echo "WARNING: you enabled distcc support, but you don't seem to be using the -jN paramter"; echo; fi +endif + @for dir in $(DIRS); do \ + $(MAKE) -C $$dir all || exit 1; \ + done +ifdef LIPO +# Lipo is an OSX thing. If it is defined, it means we are building for universal, +# and so we have have to combine the binaries into one big binary + +# Remove the last binary made by the last compiled target + $(Q)rm -f $(BIN_DIR)/$(TTD) +# Make all the binaries into one + $(Q)$(LIPO) -create -output $(BIN_DIR)/$(TTD) $(TTDS) +endif + +help: + @echo "Available make commands:" + @echo "" + @echo "Compilation:" + @echo " all compile the executable and the lang files" + @echo " lang compile the lang files only" + @echo "Clean up:" + @echo " clean remove the files generated during compilation" + @echo " mrproper remove the files generated during configuration and compilation" + @echo "Run after compilation:" + @echo " run execute openttd after the compilation" + @echo " run-gdb execute openttd in debug mode after the compilation" + @echo " run-prof execute openttd in profiling mode after the compilation" + @echo "Installation:" + @echo " install install the compiled files and the data-files after the compilation" + @echo " bundle create the base for an installation bundle" + @echo " bundle_zip create the zip installation bundle" + @echo " bundle_gzip create the gzip installation bundle" + @echo " bundle_bzip2 create the bzip2 installation bundle" + @echo " bundle_lha create the lha installation bundle" + @echo " bundle_dmg create the dmg installation bundle" + +config.pwd: $(CONFIG_CACHE_PWD) + $(MAKE) reconfigure + +config.cache: $(CONFIG_CACHE_SOURCE_LIST) $(CONFIGURE_FILES) + $(MAKE) reconfigure + +reconfigure: +ifeq ($(shell if test -f config.cache; then echo 1; fi), 1) + @echo "----------------" + @echo "The system detected that source.list or any configure file is altered." + @echo " Going to reconfigure with last known settings..." + @echo "----------------" +# Make sure we don't lock config.cache + @$(shell cat config.cache | sed 's@\\ @\\\\ @g') || exit 1 + @echo "----------------" + @echo "Reconfig done. Please re-execute make." + @echo "----------------" +else + @echo "----------------" + @echo "Have not found a configuration, please run configure first." + @echo "----------------" + @exit 1 +endif + +clean: + @for dir in $(DIRS); do \ + $(MAKE) -C $$dir clean; \ + done + $(Q)rm -rf $(BUNDLE_TARGET) + +lang: + @for dir in $(LANG_DIRS); do \ + $(MAKE) -C $$dir all; \ + done + +mrproper: + @for dir in $(DIRS); do \ + $(MAKE) -C $$dir mrproper; \ + done +# Don't be tempted to merge these two for loops. Doing that breaks make +# --dry-run, since make has this "feature" that it always runs commands +# containing $(MAKE), even when --dry-run is passed. The objective is of +# course to also get a dry-run of submakes, but make is not smart enough +# to see that a for loop runs both a submake and an actual command. + @for dir in $(DIRS); do \ + rm -f $$dir/Makefile; \ + done + $(Q)rm -rf objs + $(Q)rm -f Makefile Makefile.am Makefile.bundle + $(Q)rm -f media/openttd.desktop media/openttd.desktop.install + $(Q)rm -f $(CONFIG_CACHE_SOURCE_LIST) config.cache config.pwd config.log $(CONFIG_CACHE_PWD) +# directories for bundle generation + $(Q)rm -rf $(BUNDLE_DIR) + $(Q)rm -rf $(BUNDLES_DIR) +# output of profiling + $(Q)rm -f $(BIN_DIR)/gmon.out +# output of generating 'API' documentation + $(Q)rm -rf $(ROOT_DIR)/docs/source + $(Q)rm -rf $(ROOT_DIR)/docs/aidocs + $(Q)rm -rf $(ROOT_DIR)/docs/gamedocs +# directories created by OpenTTD on regression testing + $(Q)rm -rf $(BIN_DIR)/ai/regression/content_download $(BIN_DIR)/ai/regression/save $(BIN_DIR)/ai/regression/scenario +distclean: mrproper + +maintainer-clean: distclean + $(Q)rm -f $(BIN_DIR)/baseset/openttd.grf $(BIN_DIR)/baseset/*.obg $(BIN_DIR)/baseset/*.obs $(BIN_DIR)/baseset/*.obm + +depend: + @for dir in $(SRC_DIRS); do \ + $(MAKE) -C $$dir depend; \ + done + +run: all + $(Q)cd !!BIN_DIR!! && ./!!TTD!! $(OPENTTD_ARGS) + +run-gdb: all + $(Q)cd !!BIN_DIR!! && gdb --ex run --args ./!!TTD!! $(OPENTTD_ARGS) + +run-prof: all + $(Q)cd !!BIN_DIR!! && ./!!TTD!! $(OPENTTD_ARGS) && gprof !!TTD!! | less + +regression: all + $(Q)cd !!BIN_DIR!! && sh ai/regression/run.sh +test: regression + +%.o: + @for dir in $(SRC_DIRS); do \ + $(MAKE) -C $$dir $(@:src/%=%); \ + done + +%.lng: + @for dir in $(LANG_DIRS); do \ + $(MAKE) -C $$dir $@; \ + done + +.PHONY: test distclean mrproper clean + +include Makefile.bundle diff --git a/Makefile.lang.in b/Makefile.lang.in new file mode 100644 index 0000000..fbed06b --- /dev/null +++ b/Makefile.lang.in @@ -0,0 +1,105 @@ +# $Id$ + +# This file is part of OpenTTD. +# OpenTTD 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, version 2. +# OpenTTD 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 OpenTTD. If not, see . + +STRGEN = !!STRGEN!! +ENDIAN_CHECK = !!ENDIAN_CHECK!! +SRC_DIR = !!SRC_DIR!! +LANG_DIR = !!LANG_DIR!! +BIN_DIR = !!BIN_DIR!! +LANGS_SRC = $(shell ls $(LANG_DIR)/*.txt) +LANGS = $(LANGS_SRC:$(LANG_DIR)/%.txt=%.lng) +CXX_BUILD = !!CXX_BUILD!! +CFLAGS_BUILD = !!CFLAGS_BUILD!! +CXXFLAGS_BUILD= !!CXXFLAGS_BUILD!! +LDFLAGS_BUILD = !!LDFLAGS_BUILD!! +STRGEN_FLAGS = !!STRGEN_FLAGS!! +STAGE = !!STAGE!! +LANG_SUPPRESS = !!LANG_SUPPRESS!! +LANG_OBJS_DIR = !!LANG_OBJS_DIR!! + +ifeq ($(LANG_SUPPRESS), yes) +LANG_ERRORS = >/dev/null 2>&1 +endif + +# Make sure endian_host.h is reachable as if it was in the src/ dir +CFLAGS_BUILD += -I $(LANG_OBJS_DIR) + +ENDIAN_TARGETS := endian_host.h endian_target.h $(ENDIAN_CHECK) + +# Check if we want to show what we are doing +ifdef VERBOSE + Q = + E = @true +else + Q = @ + E = @echo +endif + +RES := $(shell mkdir -p $(BIN_DIR)/lang ) + +all: table/strings.h $(LANGS) + +strgen_base.o: $(SRC_DIR)/strgen/strgen_base.cpp $(SRC_DIR)/strgen/strgen.h endian_host.h $(SRC_DIR)/table/control_codes.h $(SRC_DIR)/table/strgen_tables.h $(SRC_DIR)/safeguards.h + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSTRGEN -c -o $@ $< + +strgen.o: $(SRC_DIR)/strgen/strgen.cpp $(SRC_DIR)/strgen/strgen.h endian_host.h $(SRC_DIR)/table/control_codes.h $(SRC_DIR)/table/strgen_tables.h $(SRC_DIR)/safeguards.h + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSTRGEN -c -o $@ $< + +string.o: $(SRC_DIR)/string.cpp endian_host.h $(SRC_DIR)/safeguards.h + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSTRGEN -c -o $@ $< + +alloc_func.o: $(SRC_DIR)/core/alloc_func.cpp endian_host.h $(SRC_DIR)/safeguards.h + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSTRGEN -c -o $@ $< + +getoptdata.o: $(SRC_DIR)/misc/getoptdata.cpp $(SRC_DIR)/misc/getoptdata.h $(SRC_DIR)/safeguards.h + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/misc/%.cpp=%.cpp)' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSTRGEN -c -o $@ $< + +lang/english.txt: $(LANG_DIR)/english.txt + $(Q)mkdir -p lang + $(Q)cp $(LANG_DIR)/english.txt lang/english.txt + +$(STRGEN): alloc_func.o string.o strgen_base.o strgen.o getoptdata.o + $(E) '$(STAGE) Compiling and Linking $@' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) $(LDFLAGS_BUILD) $^ -o $@ + +table/strings.h: lang/english.txt $(STRGEN) + $(E) '$(STAGE) Generating $@' + @mkdir -p table + $(Q)./$(STRGEN) -s $(LANG_DIR) -d table + +$(LANGS): %.lng: $(LANG_DIR)/%.txt $(STRGEN) lang/english.txt + $(E) '$(STAGE) Compiling language $(*F)' + $(Q)./$(STRGEN) $(STRGEN_FLAGS) -s $(LANG_DIR) -d $(LANG_OBJS_DIR) $< $(LANG_ERRORS) && cp $@ $(BIN_DIR)/lang || true # Do not fail all languages when one fails + +# The targets to compile the endian-code + +endian_host.h: $(ENDIAN_CHECK) + $(E) '$(STAGE) Testing endianness for host' + $(Q)./$(ENDIAN_CHECK) > $@ + +$(ENDIAN_CHECK): $(SRC_DIR)/endian_check.cpp + $(E) '$(STAGE) Compiling and Linking $@' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) $(LDFLAGS_BUILD) $< -o $@ + +depend: + +clean: + $(E) '$(STAGE) Cleaning up language files' + $(Q)rm -f strgen.o string.o alloc_func.o getoptdata.o table/strings.h $(STRGEN) $(LANGS) $(LANGS:%=$(BIN_DIR)/lang/%) lang/english.* $(ENDIAN_TARGETS) + +mrproper: clean + $(Q)rm -rf $(BIN_DIR)/lang + +%.lng: + @echo '$(STAGE) No such language: $(@:%.lng=%)' + +.PHONY: all mrproper depend clean diff --git a/Makefile.msvc b/Makefile.msvc new file mode 100644 index 0000000..0a02c8c --- /dev/null +++ b/Makefile.msvc @@ -0,0 +1,47 @@ +# $Id$ + +# This file is part of OpenTTD. +# OpenTTD 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, version 2. +# OpenTTD 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 OpenTTD. If not, see . + +# +# Makefile for creating bundles of MSVC's binaries in the same way as we make +# the zip bundles for ALL other OSes. +# +# Usage: make -f Makefile.msvc PLATFORM=[Win32|x64] BUNDLE_NAME=openttd--win[32|64] +# or make -f Makefile.msvc PLATFORM=[Win32|x64] BUNDLE_NAME=OTTD-win[32|64]-nightly- +# + +# Check if we want to show what we are doing +ifdef VERBOSE + Q = +else + Q = @ +endif + +AWK = "awk" +ROOT_DIR := $(shell pwd) +BIN_DIR = "$(ROOT_DIR)/bin" +SRC_DIR = "$(ROOT_DIR)/src" +BUNDLE_DIR = "$(ROOT_DIR)/bundle" +BUNDLES_DIR = "$(ROOT_DIR)/bundles" +TTD = openttd.exe +PDB = openttd.pdb +MODE = Release +TARGET := $(shell echo $(PLATFORM) | sed "s@win64@x64@;s@win32@Win32@") + +all: + $(Q)cp objs/$(TARGET)/$(MODE)/$(TTD) $(BIN_DIR)/$(TTD) + +include Makefile.bundle.in + +bundle_pdb: + @echo '[BUNDLE] Creating $(BUNDLE_NAME).pdb.xz' + $(Q)mkdir -p "$(BUNDLES_DIR)" + $(Q)cp objs/$(TARGET)/Release/$(PDB) $(BUNDLES_DIR)/$(BUNDLE_NAME).pdb + $(Q)xz -9 $(BUNDLES_DIR)/$(BUNDLE_NAME).pdb + +regression: all + $(Q)cp bin/$(TTD) bin/openttd + $(Q)cd bin && sh ai/regression/run.sh diff --git a/Makefile.setting.in b/Makefile.setting.in new file mode 100644 index 0000000..d89501d --- /dev/null +++ b/Makefile.setting.in @@ -0,0 +1,78 @@ +# $Id$ + +# This file is part of OpenTTD. +# OpenTTD 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, version 2. +# OpenTTD 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 OpenTTD. If not, see . + +SETTINGSGEN = !!SETTINGSGEN!! +ENDIAN_CHECK = !!ENDIAN_CHECK!! +SRC_DIR = !!SRC_DIR!! +CXX_BUILD = !!CXX_BUILD!! +CFLAGS_BUILD = !!CFLAGS_BUILD!! +CXXFLAGS_BUILD = !!CXXFLAGS_BUILD!! +LDFLAGS_BUILD = !!LDFLAGS_BUILD!! +STAGE = !!STAGE!! +SETTING_OBJS_DIR = !!SETTING_OBJS_DIR!! + +ENDIAN_TARGETS := endian_host.h endian_target.h $(ENDIAN_CHECK) + +# Check if we want to show what we are doing +ifdef VERBOSE + Q = + E = @true +else + Q = @ + E = @echo +endif + +all: table/settings.h + +settingsgen.o: $(SRC_DIR)/settingsgen/settingsgen.cpp $(SRC_DIR)/string_func.h $(SRC_DIR)/strings_type.h $(SRC_DIR)/misc/getoptdata.h $(SRC_DIR)/ini_type.h $(SRC_DIR)/core/smallvec_type.hpp $(SRC_DIR)/safeguards.h + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSETTINGSGEN -c -o $@ $< + +alloc_func.o: $(SRC_DIR)/core/alloc_func.cpp endian_host.h $(SRC_DIR)/safeguards.h + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSETTINGSGEN -c -o $@ $< + +getoptdata.o: $(SRC_DIR)/misc/getoptdata.cpp $(SRC_DIR)/misc/getoptdata.h $(SRC_DIR)/safeguards.h + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/misc/%.cpp=%.cpp)' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSETTINGSGEN -c -o $@ $< + +string.o: $(SRC_DIR)/string.cpp endian_host.h $(SRC_DIR)/safeguards.h + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSETTINGSGEN -c -o $@ $< + +ini_load.o: $(SRC_DIR)/ini_load.cpp $(SRC_DIR)/core/alloc_func.hpp $(SRC_DIR)/core/mem_func.hpp $(SRC_DIR)/ini_type.h $(SRC_DIR)/string_func.h $(SRC_DIR)/safeguards.h + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSETTINGSGEN -c -o $@ $< + +$(SETTINGSGEN): alloc_func.o string.o ini_load.o settingsgen.o getoptdata.o + $(E) '$(STAGE) Compiling and Linking $@' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) $(LDFLAGS_BUILD) $^ -o $@ + +table/settings.h: $(SETTINGSGEN) $(SRC_DIR)/table/settings.h.preamble $(SRC_DIR)/table/settings.h.postamble $(SRC_DIR)/table/*.ini + $(E) '$(STAGE) Generating $@' + @mkdir -p table + $(Q)./$(SETTINGSGEN) -o table/settings.h -b $(SRC_DIR)/table/settings.h.preamble -a $(SRC_DIR)/table/settings.h.postamble $(SRC_DIR)/table/*.ini + +# The targets to compile the endian-code + +endian_host.h: $(ENDIAN_CHECK) + $(E) '$(STAGE) Testing endianness for host' + $(Q)./$(ENDIAN_CHECK) > $@ + +$(ENDIAN_CHECK): $(SRC_DIR)/endian_check.cpp + $(E) '$(STAGE) Compiling and Linking $@' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) $(LDFLAGS_BUILD) $< -o $@ + +depend: + +clean: + $(E) '$(STAGE) Cleaning up settings files' + $(Q)rm -f settingsgen.o alloc_func.o getoptdata.o ini_load.o $(SETTINGSGEN) $(ENDIAN_TARGETS) table/settings.h + +mrproper: clean + +.PHONY: all mrproper depend clean diff --git a/Makefile.src.in b/Makefile.src.in new file mode 100644 index 0000000..1d654d2 --- /dev/null +++ b/Makefile.src.in @@ -0,0 +1,315 @@ +# $Id$ + +# This file is part of OpenTTD. +# OpenTTD 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, version 2. +# OpenTTD 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 OpenTTD. If not, see . + +CC_HOST = !!CC_HOST!! +CXX_HOST = !!CXX_HOST!! +CC_BUILD = !!CC_BUILD!! +CXX_BUILD = !!CXX_BUILD!! +WINDRES = !!WINDRES!! +STRIP = !!STRIP!! +CFLAGS = !!CFLAGS!! +CFLAGS_BUILD = !!CFLAGS_BUILD!! +CXXFLAGS = !!CXXFLAGS!! +CXXFLAGS_BUILD = !!CXXFLAGS_BUILD!! +LIBS = !!LIBS!! +LDFLAGS = !!LDFLAGS!! +LDFLAGS_BUILD = !!LDFLAGS_BUILD!! +ROOT_DIR = !!ROOT_DIR!! +BIN_DIR = !!BIN_DIR!! +LANG_DIR = !!LANG_DIR!! +SRC_OBJS_DIR = !!SRC_OBJS_DIR!! +LANG_OBJS_DIR = !!LANG_OBJS_DIR!! +SETTING_OBJS_DIR= !!SETTING_OBJS_DIR!! +SRC_DIR = !!SRC_DIR!! +SCRIPT_SRC_DIR = !!SCRIPT_SRC_DIR!! +MEDIA_DIR = !!MEDIA_DIR!! +TTD = !!TTD!! +STRGEN = !!STRGEN!! +ENDIAN_CHECK = !!ENDIAN_CHECK!! +DEPEND = !!DEPEND!! +ENDIAN_FORCE = !!ENDIAN_FORCE!! +OS = !!OS!! +STAGE = !!STAGE!! +MAKEDEPEND = !!MAKEDEPEND!! +CFLAGS_MAKEDEP = !!CFLAGS_MAKEDEP!! +SORT = !!SORT!! +AWK = !!AWK!! +CONFIG_CACHE_COMPILER = $(SRC_OBJS_DIR)/!!CONFIG_CACHE_COMPILER!! +CONFIG_CACHE_LINKER = $(SRC_OBJS_DIR)/!!CONFIG_CACHE_LINKER!! +CONFIG_CACHE_ENDIAN = $(SRC_OBJS_DIR)/!!CONFIG_CACHE_ENDIAN!! +CONFIG_CACHE_SOURCE = $(SRC_OBJS_DIR)/!!CONFIG_CACHE_SOURCE!! +CONFIG_CACHE_VERSION = $(SRC_OBJS_DIR)/!!CONFIG_CACHE_VERSION!! + +OBJS_C := !!OBJS_C!! +OBJS_CPP := !!OBJS_CPP!! +OBJS_MM := !!OBJS_MM!! +OBJS_RC := !!OBJS_RC!! +OBJS := $(OBJS_C) $(OBJS_CPP) $(OBJS_MM) $(OBJS_RC) +SRCS := !!SRCS!! + +# All C-files depend on those 3 files +FILE_DEP := $(CONFIG_CACHE_COMPILER) endian_target.h +# Create all dirs and subdirs +RES := $(shell mkdir -p $(BIN_DIR) $(sort $(dir $(OBJS)))) + +# Make sure endian_target.h is reasable as if it was in the src/ dir +CFLAGS += -I $(SRC_OBJS_DIR) -I $(LANG_OBJS_DIR) -I $(SETTING_OBJS_DIR) +CFLAGS_MAKEDEP += -I $(SRC_OBJS_DIR) -I $(LANG_OBJS_DIR) -I $(SETTING_OBJS_DIR) +ifdef SCRIPT_SRC_DIR + CFLAGS_MAKEDEP += -I $(SCRIPT_SRC_DIR) +endif + +ENDIAN_TARGETS := endian_target.h $(ENDIAN_CHECK) + +# Check if we want to show what we are doing +ifdef VERBOSE + Q = + E = @true +else + Q = @ + E = @echo +endif + +# Our default target +all: $(BIN_DIR)/$(TTD) + +# This are 2 rules that are pointing back to STRGEN stuff. +# There is not really a need to have them here, but in case +# some weirdo wants to run 'make' in the 'src' dir and expects +# the languages to be recompiled, this catches that case and +# takes care of it nicely. +$(LANG_OBJS_DIR)/$(STRGEN): + $(MAKE) -C $(LANG_OBJS_DIR) $(STRGEN) + +$(LANG_OBJS_DIR)/table/strings.h: $(LANG_DIR)/english.txt $(LANG_OBJS_DIR)/$(STRGEN) + $(MAKE) -C $(LANG_OBJS_DIR) table/strings.h + +# Always run version detection, so we always have an accurate modified +# flag +VERSIONS := $(shell AWK="$(AWK)" "$(ROOT_DIR)/findversion.sh") +MODIFIED := $(shell echo "$(VERSIONS)" | cut -f 3 -d' ') + +# Use autodetected revisions +REV := $(shell echo "$(VERSIONS)" | cut -f 1 -d' ') +REV_NR := $(shell echo "$(VERSIONS)" | cut -f 2 -d' ') + +# Make sure we have something in REV and REV_NR +ifeq ($(REV),) +REV := norev000 +endif +ifeq ($(REV_NR),) +REV_NR := 0 +endif + +# This helps to recompile if flags change +RES := $(shell if [ "`cat $(CONFIG_CACHE_COMPILER) 2>/dev/null`" != "$(CFLAGS) $(CXXFLAGS)" ]; then echo "$(CFLAGS) $(CXXFLAGS)" > $(CONFIG_CACHE_COMPILER); fi ) +RES := $(shell if [ "`cat $(CONFIG_CACHE_LINKER) 2>/dev/null`" != "$(LDFLAGS) $(LIBS)" ]; then echo "$(LDFLAGS) $(LIBS)" > $(CONFIG_CACHE_LINKER); fi ) +RES := $(shell if [ "`cat $(CONFIG_CACHE_ENDIAN) 2>/dev/null`" != "$(ENDIAN_FORCE)" ]; then echo "$(ENDIAN_FORCE)" > $(CONFIG_CACHE_ENDIAN); fi ) + +# If there is a change in the source-file-list, make sure we recheck the deps +RES := $(shell if [ "`cat $(CONFIG_CACHE_SOURCE) 2>/dev/null`" != "$(SRCS)" ]; then echo "$(SRCS)" > $(CONFIG_CACHE_SOURCE); fi ) +# If there is a change in the revision, make sure we recompile rev.cpp +RES := $(shell if [ "`cat $(CONFIG_CACHE_VERSION) 2>/dev/null`" != "$(REV) $(MODIFIED)" ]; then echo "$(REV) $(MODIFIED)" > $(CONFIG_CACHE_VERSION); fi ) + +ifndef MAKEDEPEND +# The slow, but always correct, dep-check +DEP_MASK := %.d +DEPS := $(OBJS:%.o=%.d) + +# Only include the deps if we are compiling everything +ifeq ($(filter $(ENDIAN_TARGETS) %.o clean mrproper, $(MAKECMDGOALS)),) +-include $(DEPS) +else +# In case we want to compile a single target, include the .d file for it +ifneq ($(filter %.o, $(MAKECMDGOALS)),) +SINGLE_DEP := $(filter %.o, $(MAKECMDGOALS)) +-include $(SINGLE_DEP:%.o=%.d) +endif +endif + +# Find the deps via GCC. Rarely wrong, but a bit slow + +$(OBJS_C:%.o=%.d): %.d: $(SRC_DIR)/%.c $(FILE_DEP) + $(E) '$(STAGE) DEP $(<:$(SRC_DIR)/%.c=%.c)' + $(Q)$(CC_HOST) $(CFLAGS) -MM $< | sed 's@^$(@F:%.d=%.o):@$@ $(@:%.d=%.o):@' > $@ + +$(OBJS_CPP:%.o=%.d): %.d: $(SRC_DIR)/%.cpp $(FILE_DEP) + $(E) '$(STAGE) DEP $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_HOST) $(CFLAGS) $(CXXFLAGS) -MM $< | sed 's@^$(@F:%.d=%.o):@$@ $(@:%.d=%.o):@' > $@ + +$(OBJS_MM:%.o=%.d): %.d: $(SRC_DIR)/%.mm $(FILE_DEP) + $(E) '$(STAGE) DEP $(<:$(SRC_DIR)/%.mm=%.mm)' + $(Q)$(CC_HOST) $(CFLAGS) -MM $< | sed 's@^$(@F:%.d=%.o):@$@ $(@:%.d=%.o):@' > $@ + +$(OBJS_RC:%.o=%.d): %.d: $(SRC_DIR)/%.rc $(FILE_DEP) + $(E) '$(STAGE) DEP $(<:$(SRC_DIR)/%.rc=%.rc)' + $(Q)touch $@ + +else +# The much faster, but can be wrong, dep-check +DEP_MASK := +DEPS := Makefile.dep + +# Only include the deps if we are not cleaning +ifeq ($(filter $(ENDIAN_TARGETS) depend clean mrproper, $(MAKECMDGOALS)),) +-include Makefile.dep +endif + +ifeq ("$(SRC_OBJS_DIR)/$(DEPEND)","$(MAKEDEPEND)") +DEP := $(MAKEDEPEND) +$(SRC_OBJS_DIR)/$(DEPEND): $(SRC_DIR)/depend/depend.cpp + $(E) '$(STAGE) Compiling and linking $(DEPEND)' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) $(LDFLAGS_BUILD) -o $@ $< +endif + +# Make sure that only 'make depend' ALWAYS triggers a recheck +ifeq ($(filter depend, $(MAKECMDGOALS)),) +Makefile.dep: $(FILE_DEP) $(SRCS:%=$(SRC_DIR)/%) $(CONFIG_CACHE_SOURCE) $(DEP) +else +Makefile.dep: $(FILE_DEP) $(SRCS:%=$(SRC_DIR)/%) $(DEP) FORCE +endif + $(E) '$(STAGE) DEP CHECK (all files)' + $(Q)rm -f Makefile.dep.tmp + $(Q)touch Makefile.dep.tmp + +# Calculate the deps via makedepend + $(Q)$(MAKEDEPEND) -f$(SRC_OBJS_DIR)/Makefile.dep.tmp -o.o -Y -v -- $(CFLAGS_MAKEDEP) -- $(SRCS:%=$(SRC_DIR)/%) 2>/dev/null + +# Convert x:/... paths to /x/... for mingw +ifeq ($(OS), MINGW) + @cat Makefile.dep.tmp | sed 's@/\([a-zA-Z]\):\/@\/\1\/@g' > Makefile.dep.tmp.mingw + @cp Makefile.dep.tmp.mingw Makefile.dep.tmp + @rm -f Makefile.dep.tmp.mingw +endif + +# Remove all comments and includes that don't start with $(SRC_DIR) +# Remove $(SRC_DIR) from object-file-name + @$(AWK) ' \ + /^# DO NOT/ { print $$0 ; next} \ + /^#/ {next} \ + /: / { \ + left = NF - 1; \ + for (n = 2; n <= NF; n++) { \ + if (match($$n, "^$(ROOT_DIR)") == 0) { \ + $$n = ""; \ + left--; \ + } \ + } \ + gsub("$(SRC_DIR)/", "", $$1); \ + if (left > 0) { \ + print $$0; \ + $$1 = "Makefile.dep:"; \ + print $$0; \ + } \ + next \ + } \ + { \ + print $$0 \ + } \ + ' < Makefile.dep.tmp | sed 's@ *@ @g;s@ $$@@' | $(SORT) > Makefile.dep + + $(Q)rm -f Makefile.dep.tmp Makefile.dep.tmp.bak + +endif + +# Avoid problems with deps if a .h/.hpp/.hpp.sq file is deleted without the deps +# being updated. Now the Makefile continues, the deps are recreated +# and all will be fine. +%.h %.hpp %.hpp.sq: + @true + + +# Compile all the files according to the targets + +$(OBJS_C): %.o: $(SRC_DIR)/%.c $(DEP_MASK) $(FILE_DEP) + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.c=%.c)' + $(Q)$(CC_HOST) $(CFLAGS) -c -o $@ $< + +$(filter-out %sse2.o, $(filter-out %ssse3.o, $(filter-out %sse4.o, $(OBJS_CPP)))): %.o: $(SRC_DIR)/%.cpp $(DEP_MASK) $(FILE_DEP) + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_HOST) $(CFLAGS) $(CXXFLAGS) -c -o $@ $< + +$(filter %sse2.o, $(OBJS_CPP)): %.o: $(SRC_DIR)/%.cpp $(DEP_MASK) $(FILE_DEP) + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_HOST) $(CFLAGS) $(CXXFLAGS) -c -msse2 -o $@ $< + +$(filter %ssse3.o, $(OBJS_CPP)): %.o: $(SRC_DIR)/%.cpp $(DEP_MASK) $(FILE_DEP) + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_HOST) $(CFLAGS) $(CXXFLAGS) -c -mssse3 -o $@ $< + +$(filter %sse4.o, $(OBJS_CPP)): %.o: $(SRC_DIR)/%.cpp $(DEP_MASK) $(FILE_DEP) + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_HOST) $(CFLAGS) $(CXXFLAGS) -c -msse4.1 -o $@ $< + +$(OBJS_MM): %.o: $(SRC_DIR)/%.mm $(DEP_MASK) $(FILE_DEP) + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.mm=%.mm)' + $(Q)$(CC_HOST) $(CFLAGS) -c -o $@ $< + +$(OBJS_RC): %.o: $(SRC_DIR)/%.rc $(FILE_DEP) + $(E) '$(STAGE) Compiling resource $(<:$(SRC_DIR)/%.rc=%.rc)' + $(Q)$(WINDRES) -o $@ -I `basename $<` $< + +$(BIN_DIR)/$(TTD): $(TTD) + $(Q)cp $(TTD) $(BIN_DIR)/$(TTD) +ifeq ($(OS), UNIX) + $(Q)cp $(MEDIA_DIR)/openttd.32.bmp $(BIN_DIR)/baseset/ +endif +ifeq ($(OS), OSX) + $(Q)cp $(ROOT_DIR)/os/macosx/splash.png $(BIN_DIR)/baseset/ +endif + +$(TTD): $(OBJS) $(CONFIG_CACHE_LINKER) + $(E) '$(STAGE) Linking $@' +ifeq ($(OS), PSP) + # Because of a bug in the PSP GCC tools, linking via CXX results + # in total chaos and more problems then you can handle. So we need + # CC to link OpenTTD for PSP + $(Q)+$(CC_HOST) $(LDFLAGS) $(OBJS) $(LIBS) -o $@ +else + $(Q)+$(CXX_HOST) $(LDFLAGS) $(OBJS) $(LIBS) -o $@ +endif +ifdef STRIP + $(Q)$(STRIP) $@ +endif +ifeq ($(OS), DOS) + $(E) '$(STAGE) Adding CWSDPMI stub to $@' + $(Q)$(ROOT_DIR)/os/dos/make_dos_binary_selfcontained.sh $(SRC_OBJS_DIR)/$@ +endif + +# The targets to compile the endian-code + +endian_target.h: $(ENDIAN_CHECK) $(CONFIG_CACHE_ENDIAN) + $(E) '$(STAGE) Testing endianness for target' + $(Q)./$(ENDIAN_CHECK) $(ENDIAN_FORCE) > $@ + +$(ENDIAN_CHECK): $(SRC_DIR)/endian_check.cpp + $(E) '$(STAGE) Compiling and Linking $@' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) $(LDFLAGS_BUILD) $< -o $@ + +# Revision files + +$(SRC_DIR)/rev.cpp: $(CONFIG_CACHE_VERSION) $(SRC_DIR)/rev.cpp.in + $(Q)cat $(SRC_DIR)/rev.cpp.in | sed "s@\!\!REVISION\!\!@$(REV_NR)@g;s@!!VERSION!!@$(REV)@g;s@!!MODIFIED!!@$(MODIFIED)@g;s@!!DATE!!@`date +%d.%m.%y`@g" > $(SRC_DIR)/rev.cpp + +$(SRC_DIR)/os/windows/ottdres.rc: $(CONFIG_CACHE_VERSION) $(SRC_DIR)/os/windows/ottdres.rc.in + $(Q)cat $(SRC_DIR)/os/windows/ottdres.rc.in | sed "s@\!\!REVISION\!\!@$(REV_NR)@g;s@!!VERSION!!@$(REV)@g;s@!!DATE!!@`date +%d.%m.%y`@g" > $(SRC_DIR)/os/windows/ottdres.rc + +FORCE: + +depend: $(DEPS) + +clean: + $(E) '$(STAGE) Cleaning up object files' + $(Q)rm -f $(DEPS) $(OBJS) $(TTD) $(DEPEND) $(TTD:%=$(BIN_DIR)/%) $(BIN_DIR)/baseset/openttd.32.bmp $(CONFIG_CACHE_COMPILER) $(CONFIG_CACHE_LINKER) $(CONFIG_CACHE_ENDIAN) $(CONFIG_CACHE_SOURCE) $(ENDIAN_TARGETS) + +mrproper: clean + $(Q)rm -f $(SRC_DIR)/rev.cpp $(SRC_DIR)/os/windows/ottdres.rc + +%.o: + @echo '$(STAGE) No such source-file: $(@:%.o=%).[c|cpp|mm|rc]' + +.PHONY: all mrproper depend clean FORCE diff --git a/bin/ai/compat_0.7.nut b/bin/ai/compat_0.7.nut new file mode 100644 index 0000000..44e6acf --- /dev/null +++ b/bin/ai/compat_0.7.nut @@ -0,0 +1,369 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +AILog.Info("0.7 API compatibility in effect:"); +AILog.Info(" - AITown::GetLastMonthProduction's behaviour has slightly changed."); +AILog.Info(" - AISubsidy::GetDestination returns STATION_INVALID for awarded subsidies."); +AILog.Info(" - AISubsidy::GetSource returns STATION_INVALID for awarded subsidies."); + +AISign.GetMaxSignID <- function() +{ + local list = AISignList(); + local max_id = 0; + foreach (id, d in list) { + if (id > max_id) max_id = id; + } + return max_id; +} + +AITile.GetHeight <- function(tile) +{ + if (!AIMap.IsValidTile(tile)) return -1; + + return AITile.GetCornerHeight(tile, AITile.CORNER_N); +} + +AIOrder.ChangeOrder <- function(vehicle_id, order_position, order_flags) +{ + return AIOrder.SetOrderFlags(vehicle_id, order_position, order_flags); +} + +AIWaypoint.WAYPOINT_INVALID <- 0xFFFF; + +AISubsidy.SourceIsTown <- function(subsidy_id) +{ + if (!AISubsidy.IsValidSubsidy(subsidy_id) || AISubsidy.IsAwarded(subsidy_id)) return false; + + return AISubsidy.GetSourceType(subsidy_id) == AISubsidy.SPT_TOWN; +} + +AISubsidy.GetSource <- function(subsidy_id) +{ + if (!AISubsidy.IsValidSubsidy(subsidy_id)) return AIBaseStation.STATION_INVALID; + + if (AISubsidy.IsAwarded(subsidy_id)) { + return AIBaseStation.STATION_INVALID; + } + + return AISubsidy.GetSourceIndex(subsidy_id); +} + +AISubsidy.DestinationIsTown <- function(subsidy_id) +{ + if (!AISubsidy.IsValidSubsidy(subsidy_id) || AISubsidy.IsAwarded(subsidy_id)) return false; + + return AISubsidy.GetDestinationType(subsidy_id) == AISubsidy.SPT_TOWN; +} + +AISubsidy.GetDestination <- function(subsidy_id) +{ + if (!AISubsidy.IsValidSubsidy(subsidy_id)) return AIBaseStation.STATION_INVALID; + + if (AISubsidy.IsAwarded(subsidy_id)) { + return AIBaseStation.STATION_INVALID; + } + + return AISubsidy.GetDestinationIndex(subsidy_id); +} + +AITown.GetMaxProduction <- function(town_id, cargo_id) +{ + return AITown.GetLastMonthProduction(town_id, cargo_id); +} + +AIRail.RemoveRailWaypoint <- function(tile) +{ + return AIRail.RemoveRailWaypointTileRect(tile, tile, true); +} + +AIRail.RemoveRailStationTileRect <- function(tile, tile2) +{ + return AIRail.RemoveRailStationTileRectangle(tile, tile2, false); +} + +AIVehicle.SkipToVehicleOrder <- function(vehicle_id, order_position) +{ + return AIOrder.SkipToOrder(vehicle_id, order_position); +} + +AIEngine.IsValidEngine <- function(engine_id) +{ + return AIEngine.IsBuildable(engine_id); +} + +AIEngine._GetName <- AIEngine.GetName; +AIEngine.GetName <- function(engine_id) +{ + if (!AIEngine.IsBuildable(engine_id)) return null; + return AIEngine._GetName(engine_id); +} + +AIEngine._GetCargoType <- AIEngine.GetCargoType; +AIEngine.GetCargoType <- function(engine_id) +{ + if (!AIEngine.IsBuildable(engine_id)) return 255; + return AIEngine._GetCargoType(engine_id); +} + +AIEngine._CanRefitCargo <- AIEngine.CanRefitCargo; +AIEngine.CanRefitCargo <- function(engine_id, cargo_id) +{ + if (!AIEngine.IsBuildable(engine_id)) return false; + return AIEngine._CanRefitCargo(engine_id, cargo_id); +} + +AIEngine._CanPullCargo <- AIEngine.CanPullCargo; +AIEngine.CanPullCargo <- function(engine_id, cargo_id) +{ + if (!AIEngine.IsBuildable(engine_id)) return false; + return AIEngine._CanPullCargo(engine_id, cargo_id); +} + +AIEngine._GetCapacity <- AIEngine.GetCapacity; +AIEngine.GetCapacity <- function(engine_id) +{ + if (!AIEngine.IsBuildable(engine_id)) return -1; + return AIEngine._GetCapacity(engine_id); +} + +AIEngine._GetReliability <- AIEngine.GetReliability; +AIEngine.GetReliability <- function(engine_id) +{ + if (!AIEngine.IsBuildable(engine_id)) return -1; + return AIEngine._GetReliability(engine_id); +} + +AIEngine._GetMaxSpeed <- AIEngine.GetMaxSpeed; +AIEngine.GetMaxSpeed <- function(engine_id) +{ + if (!AIEngine.IsBuildable(engine_id)) return -1; + return AIEngine._GetMaxSpeed(engine_id); +} + +AIEngine._GetPrice <- AIEngine.GetPrice; +AIEngine.GetPrice <- function(engine_id) +{ + if (!AIEngine.IsBuildable(engine_id)) return -1; + return AIEngine._GetPrice(engine_id); +} + +AIEngine._GetMaxAge <- AIEngine.GetMaxAge; +AIEngine.GetMaxAge <- function(engine_id) +{ + if (!AIEngine.IsBuildable(engine_id)) return -1; + return AIEngine._GetMaxAge(engine_id); +} + +AIEngine._GetRunningCost <- AIEngine.GetRunningCost; +AIEngine.GetRunningCost <- function(engine_id) +{ + if (!AIEngine.IsBuildable(engine_id)) return -1; + return AIEngine._GetRunningCost(engine_id); +} + +AIEngine._GetPower <- AIEngine.GetPower; +AIEngine.GetPower <- function(engine_id) +{ + if (!AIEngine.IsBuildable(engine_id)) return -1; + return AIEngine._GetPower(engine_id); +} + +AIEngine._GetWeight <- AIEngine.GetWeight; +AIEngine.GetWeight <- function(engine_id) +{ + if (!AIEngine.IsBuildable(engine_id)) return -1; + return AIEngine._GetWeight(engine_id); +} + +AIEngine._GetMaxTractiveEffort <- AIEngine.GetMaxTractiveEffort; +AIEngine.GetMaxTractiveEffort <- function(engine_id) +{ + if (!AIEngine.IsBuildable(engine_id)) return -1; + return AIEngine._GetMaxTractiveEffort(engine_id); +} + +AIEngine._GetDesignDate <- AIEngine.GetDesignDate; +AIEngine.GetDesignDate <- function(engine_id) +{ + if (!AIEngine.IsBuildable(engine_id)) return -1; + return AIEngine._GetDesignDate(engine_id); +} + +AIEngine._GetVehicleType <- AIEngine.GetVehicleType; +AIEngine.GetVehicleType <- function(engine_id) +{ + if (!AIEngine.IsBuildable(engine_id)) return AIVehicle.VT_INVALID; + return AIEngine._GetVehicleType(engine_id); +} + +AIEngine._IsWagon <- AIEngine.IsWagon; +AIEngine.IsWagon <- function(engine_id) +{ + if (!AIEngine.IsBuildable(engine_id)) return false; + return AIEngine._IsWagon(engine_id); +} + +AIEngine._CanRunOnRail <- AIEngine.CanRunOnRail; +AIEngine.CanRunOnRail <- function(engine_id, track_rail_type) +{ + if (!AIEngine.IsBuildable(engine_id)) return false; + return AIEngine._CanRunOnRail(engine_id, track_rail_type); +} + +AIEngine._HasPowerOnRail <- AIEngine.HasPowerOnRail; +AIEngine.HasPowerOnRail <- function(engine_id, track_rail_type) +{ + if (!AIEngine.IsBuildable(engine_id)) return false; + return AIEngine._HasPowerOnRail(engine_id, track_rail_type); +} + +AIEngine._GetRoadType <- AIEngine.GetRoadType; +AIEngine.GetRoadType <- function(engine_id) +{ + if (!AIEngine.IsBuildable(engine_id)) return AIRoad.ROADTYPE_INVALID; + return AIEngine._GetRoadType(engine_id); +} + +AIEngine._GetRailType <- AIEngine.GetRailType; +AIEngine.GetRailType <- function(engine_id) +{ + if (!AIEngine.IsBuildable(engine_id)) return AIRail.RAILTYPE_INVALID; + return AIEngine._GetRailType(engine_id); +} + +AIEngine._IsArticulated <- AIEngine.IsArticulated; +AIEngine.IsArticulated <- function(engine_id) +{ + if (!AIEngine.IsBuildable(engine_id)) return false; + return AIEngine._IsArticulated(engine_id); +} + +AIEngine._GetPlaneType <- AIEngine.GetPlaneType; +AIEngine.GetPlaneType <- function(engine_id) +{ + if (!AIEngine.IsBuildable(engine_id)) return -1; + return AIEngine._GetPlaneType(engine_id); +} + +_AIWaypointList <- AIWaypointList; +class AIWaypointList extends _AIWaypointList { + constructor() + { + ::_AIWaypointList.constructor(AIWaypoint.WAYPOINT_RAIL); + } +} + +AIRoad._BuildRoadStation <- AIRoad.BuildRoadStation; +AIRoad.BuildRoadStation <- function(tile, front, road_veh_type, station_id) +{ + if (AIRoad.IsRoadStationTile(tile) && AICompany.IsMine(AITile.GetOwner(tile))) return false; + + return AIRoad._BuildRoadStation(tile, front, road_veh_type, station_id); +} + +AIRoad._BuildDriveThroughRoadStation <- AIRoad.BuildDriveThroughRoadStation; +AIRoad.BuildDriveThroughRoadStation <- function(tile, front, road_veh_type, station_id) +{ + if (AIRoad.IsRoadStationTile(tile) && AICompany.IsMine(AITile.GetOwner(tile))) return false; + + return AIRoad._BuildDriveThroughRoadStation(tile, front, road_veh_type, station_id); +} + +AIBridgeList.HasNext <- +AIBridgeList_Length.HasNext <- +AICargoList.HasNext <- +AICargoList_IndustryAccepting.HasNext <- +AICargoList_IndustryProducing.HasNext <- +AIDepotList.HasNext <- +AIEngineList.HasNext <- +AIGroupList.HasNext <- +AIIndustryList.HasNext <- +AIIndustryList_CargoAccepting.HasNext <- +AIIndustryList_CargoProducing.HasNext <- +AIIndustryTypeList.HasNext <- +AIList.HasNext <- +AIRailTypeList.HasNext <- +AISignList.HasNext <- +AIStationList.HasNext <- +AIStationList_Vehicle.HasNext <- +AISubsidyList.HasNext <- +AITileList.HasNext <- +AITileList_IndustryAccepting.HasNext <- +AITileList_IndustryProducing.HasNext <- +AITileList_StationType.HasNext <- +AITownList.HasNext <- +AIVehicleList.HasNext <- +AIVehicleList_DefaultGroup.HasNext <- +AIVehicleList_Group.HasNext <- +AIVehicleList_SharedOrders.HasNext <- +AIVehicleList_Station.HasNext <- +AIWaypointList.HasNext <- +AIWaypointList_Vehicle.HasNext <- +function() +{ + return !this.IsEnd(); +} + +AIIndustry._IsCargoAccepted <- AIIndustry.IsCargoAccepted; +AIIndustry.IsCargoAccepted <- function(industry_id, cargo_id) +{ + return AIIndustry._IsCargoAccepted(industry_id, cargo_id) != AIIndustry.CAS_NOT_ACCEPTED; +} + +AIAbstractList <- AIList; + +AIList.ChangeItem <- AIList.SetValue; + +AIRail.ERR_NONUNIFORM_STATIONS_DISABLED <- 0xFFFF; + +AICompany.GetCompanyValue <- function(company) +{ + return AICompany.GetQuarterlyCompanyValue(company, AICompany.CURRENT_QUARTER); +} + +AITown.GetLastMonthTransported <- AITown.GetLastMonthSupplied; + +AIEvent.AI_ET_INVALID <- AIEvent.ET_INVALID; +AIEvent.AI_ET_TEST <- AIEvent.ET_TEST; +AIEvent.AI_ET_SUBSIDY_OFFER <- AIEvent.ET_SUBSIDY_OFFER; +AIEvent.AI_ET_SUBSIDY_OFFER_EXPIRED <- AIEvent.ET_SUBSIDY_OFFER_EXPIRED; +AIEvent.AI_ET_SUBSIDY_AWARDED <- AIEvent.ET_SUBSIDY_AWARDED; +AIEvent.AI_ET_SUBSIDY_EXPIRED <- AIEvent.ET_SUBSIDY_EXPIRED; +AIEvent.AI_ET_ENGINE_PREVIEW <- AIEvent.ET_ENGINE_PREVIEW; +AIEvent.AI_ET_COMPANY_NEW <- AIEvent.ET_COMPANY_NEW; +AIEvent.AI_ET_COMPANY_IN_TROUBLE <- AIEvent.ET_COMPANY_IN_TROUBLE; +AIEvent.AI_ET_COMPANY_MERGER <- AIEvent.ET_COMPANY_MERGER; +AIEvent.AI_ET_COMPANY_BANKRUPT <- AIEvent.ET_COMPANY_BANKRUPT; +AIEvent.AI_ET_VEHICLE_CRASHED <- AIEvent.ET_VEHICLE_CRASHED; +AIEvent.AI_ET_VEHICLE_LOST <- AIEvent.ET_VEHICLE_LOST; +AIEvent.AI_ET_VEHICLE_WAITING_IN_DEPOT <- AIEvent.ET_VEHICLE_WAITING_IN_DEPOT; +AIEvent.AI_ET_VEHICLE_UNPROFITABLE <- AIEvent.ET_VEHICLE_UNPROFITABLE; +AIEvent.AI_ET_INDUSTRY_OPEN <- AIEvent.ET_INDUSTRY_OPEN; +AIEvent.AI_ET_INDUSTRY_CLOSE <- AIEvent.ET_INDUSTRY_CLOSE; +AIEvent.AI_ET_ENGINE_AVAILABLE <- AIEvent.ET_ENGINE_AVAILABLE; +AIEvent.AI_ET_STATION_FIRST_VEHICLE <- AIEvent.ET_STATION_FIRST_VEHICLE; +AIEvent.AI_ET_DISASTER_ZEPPELINER_CRASHED <- AIEvent.ET_DISASTER_ZEPPELINER_CRASHED; +AIEvent.AI_ET_DISASTER_ZEPPELINER_CLEARED <- AIEvent.ET_DISASTER_ZEPPELINER_CLEARED; +AIOrder.AIOF_NONE <- AIOrder.OF_NONE +AIOrder.AIOF_NON_STOP_INTERMEDIATE <- AIOrder.OF_NON_STOP_INTERMEDIATE +AIOrder.AIOF_NON_STOP_DESTINATION <- AIOrder.OF_NON_STOP_DESTINATION +AIOrder.AIOF_UNLOAD <- AIOrder.OF_UNLOAD +AIOrder.AIOF_TRANSFER <- AIOrder.OF_TRANSFER +AIOrder.AIOF_NO_UNLOAD <- AIOrder.OF_NO_UNLOAD +AIOrder.AIOF_FULL_LOAD <- AIOrder.OF_FULL_LOAD +AIOrder.AIOF_FULL_LOAD_ANY <- AIOrder.OF_FULL_LOAD_ANY +AIOrder.AIOF_NO_LOAD <- AIOrder.OF_NO_LOAD +AIOrder.AIOF_SERVICE_IF_NEEDED <- AIOrder.OF_SERVICE_IF_NEEDED +AIOrder.AIOF_STOP_IN_DEPOT <- AIOrder.OF_STOP_IN_DEPOT +AIOrder.AIOF_GOTO_NEAREST_DEPOT <- AIOrder.OF_GOTO_NEAREST_DEPOT +AIOrder.AIOF_NON_STOP_FLAGS <- AIOrder.OF_NON_STOP_FLAGS +AIOrder.AIOF_UNLOAD_FLAGS <- AIOrder.OF_UNLOAD_FLAGS +AIOrder.AIOF_LOAD_FLAGS <- AIOrder.OF_LOAD_FLAGS +AIOrder.AIOF_DEPOT_FLAGS <- AIOrder.OF_DEPOT_FLAGS +AIOrder.AIOF_INVALID <- AIOrder.OF_INVALID diff --git a/bin/ai/compat_1.0.nut b/bin/ai/compat_1.0.nut new file mode 100644 index 0000000..5e7dd44 --- /dev/null +++ b/bin/ai/compat_1.0.nut @@ -0,0 +1,121 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +AILog.Info("1.0 API compatibility in effect."); + +AIRoad._BuildRoadStation <- AIRoad.BuildRoadStation; +AIRoad.BuildRoadStation <- function(tile, front, road_veh_type, station_id) +{ + if (AIRoad.IsRoadStationTile(tile) && AICompany.IsMine(AITile.GetOwner(tile))) return false; + + return AIRoad._BuildRoadStation(tile, front, road_veh_type, station_id); +} + +AIRoad._BuildDriveThroughRoadStation <- AIRoad.BuildDriveThroughRoadStation; +AIRoad.BuildDriveThroughRoadStation <- function(tile, front, road_veh_type, station_id) +{ + if (AIRoad.IsRoadStationTile(tile) && AICompany.IsMine(AITile.GetOwner(tile))) return false; + + return AIRoad._BuildDriveThroughRoadStation(tile, front, road_veh_type, station_id); +} + +AIBridgeList.HasNext <- +AIBridgeList_Length.HasNext <- +AICargoList.HasNext <- +AICargoList_IndustryAccepting.HasNext <- +AICargoList_IndustryProducing.HasNext <- +AIDepotList.HasNext <- +AIEngineList.HasNext <- +AIGroupList.HasNext <- +AIIndustryList.HasNext <- +AIIndustryList_CargoAccepting.HasNext <- +AIIndustryList_CargoProducing.HasNext <- +AIIndustryTypeList.HasNext <- +AIList.HasNext <- +AIRailTypeList.HasNext <- +AISignList.HasNext <- +AIStationList.HasNext <- +AIStationList_Vehicle.HasNext <- +AISubsidyList.HasNext <- +AITileList.HasNext <- +AITileList_IndustryAccepting.HasNext <- +AITileList_IndustryProducing.HasNext <- +AITileList_StationType.HasNext <- +AITownList.HasNext <- +AIVehicleList.HasNext <- +AIVehicleList_DefaultGroup.HasNext <- +AIVehicleList_Depot.HasNext <- +AIVehicleList_Group.HasNext <- +AIVehicleList_SharedOrders.HasNext <- +AIVehicleList_Station.HasNext <- +AIWaypointList.HasNext <- +AIWaypointList_Vehicle.HasNext <- +function() +{ + return !this.IsEnd(); +} + +AIIndustry._IsCargoAccepted <- AIIndustry.IsCargoAccepted; +AIIndustry.IsCargoAccepted <- function(industry_id, cargo_id) +{ + return AIIndustry._IsCargoAccepted(industry_id, cargo_id) != AIIndustry.CAS_NOT_ACCEPTED; +} + +AIAbstractList <- AIList; + +AIList.ChangeItem <- AIList.SetValue; + +AIRail.ERR_NONUNIFORM_STATIONS_DISABLED <- 0xFFFF; + +AICompany.GetCompanyValue <- function(company) +{ + return AICompany.GetQuarterlyCompanyValue(company, AICompany.CURRENT_QUARTER); +} + +AITown.GetLastMonthTransported <- AITown.GetLastMonthSupplied; + +AIEvent.AI_ET_INVALID <- AIEvent.ET_INVALID; +AIEvent.AI_ET_TEST <- AIEvent.ET_TEST; +AIEvent.AI_ET_SUBSIDY_OFFER <- AIEvent.ET_SUBSIDY_OFFER; +AIEvent.AI_ET_SUBSIDY_OFFER_EXPIRED <- AIEvent.ET_SUBSIDY_OFFER_EXPIRED; +AIEvent.AI_ET_SUBSIDY_AWARDED <- AIEvent.ET_SUBSIDY_AWARDED; +AIEvent.AI_ET_SUBSIDY_EXPIRED <- AIEvent.ET_SUBSIDY_EXPIRED; +AIEvent.AI_ET_ENGINE_PREVIEW <- AIEvent.ET_ENGINE_PREVIEW; +AIEvent.AI_ET_COMPANY_NEW <- AIEvent.ET_COMPANY_NEW; +AIEvent.AI_ET_COMPANY_IN_TROUBLE <- AIEvent.ET_COMPANY_IN_TROUBLE; +AIEvent.AI_ET_COMPANY_ASK_MERGER <- AIEvent.ET_COMPANY_ASK_MERGER; +AIEvent.AI_ET_COMPANY_MERGER <- AIEvent.ET_COMPANY_MERGER; +AIEvent.AI_ET_COMPANY_BANKRUPT <- AIEvent.ET_COMPANY_BANKRUPT; +AIEvent.AI_ET_VEHICLE_CRASHED <- AIEvent.ET_VEHICLE_CRASHED; +AIEvent.AI_ET_VEHICLE_LOST <- AIEvent.ET_VEHICLE_LOST; +AIEvent.AI_ET_VEHICLE_WAITING_IN_DEPOT <- AIEvent.ET_VEHICLE_WAITING_IN_DEPOT; +AIEvent.AI_ET_VEHICLE_UNPROFITABLE <- AIEvent.ET_VEHICLE_UNPROFITABLE; +AIEvent.AI_ET_INDUSTRY_OPEN <- AIEvent.ET_INDUSTRY_OPEN; +AIEvent.AI_ET_INDUSTRY_CLOSE <- AIEvent.ET_INDUSTRY_CLOSE; +AIEvent.AI_ET_ENGINE_AVAILABLE <- AIEvent.ET_ENGINE_AVAILABLE; +AIEvent.AI_ET_STATION_FIRST_VEHICLE <- AIEvent.ET_STATION_FIRST_VEHICLE; +AIEvent.AI_ET_DISASTER_ZEPPELINER_CRASHED <- AIEvent.ET_DISASTER_ZEPPELINER_CRASHED; +AIEvent.AI_ET_DISASTER_ZEPPELINER_CLEARED <- AIEvent.ET_DISASTER_ZEPPELINER_CLEARED; +AIOrder.AIOF_NONE <- AIOrder.OF_NONE +AIOrder.AIOF_NON_STOP_INTERMEDIATE <- AIOrder.OF_NON_STOP_INTERMEDIATE +AIOrder.AIOF_NON_STOP_DESTINATION <- AIOrder.OF_NON_STOP_DESTINATION +AIOrder.AIOF_UNLOAD <- AIOrder.OF_UNLOAD +AIOrder.AIOF_TRANSFER <- AIOrder.OF_TRANSFER +AIOrder.AIOF_NO_UNLOAD <- AIOrder.OF_NO_UNLOAD +AIOrder.AIOF_FULL_LOAD <- AIOrder.OF_FULL_LOAD +AIOrder.AIOF_FULL_LOAD_ANY <- AIOrder.OF_FULL_LOAD_ANY +AIOrder.AIOF_NO_LOAD <- AIOrder.OF_NO_LOAD +AIOrder.AIOF_SERVICE_IF_NEEDED <- AIOrder.OF_SERVICE_IF_NEEDED +AIOrder.AIOF_STOP_IN_DEPOT <- AIOrder.OF_STOP_IN_DEPOT +AIOrder.AIOF_GOTO_NEAREST_DEPOT <- AIOrder.OF_GOTO_NEAREST_DEPOT +AIOrder.AIOF_NON_STOP_FLAGS <- AIOrder.OF_NON_STOP_FLAGS +AIOrder.AIOF_UNLOAD_FLAGS <- AIOrder.OF_UNLOAD_FLAGS +AIOrder.AIOF_LOAD_FLAGS <- AIOrder.OF_LOAD_FLAGS +AIOrder.AIOF_DEPOT_FLAGS <- AIOrder.OF_DEPOT_FLAGS +AIOrder.AIOF_INVALID <- AIOrder.OF_INVALID diff --git a/bin/ai/compat_1.1.nut b/bin/ai/compat_1.1.nut new file mode 100644 index 0000000..32127b4 --- /dev/null +++ b/bin/ai/compat_1.1.nut @@ -0,0 +1,58 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +AILog.Info("1.1 API compatibility in effect."); + +AICompany.GetCompanyValue <- function(company) +{ + return AICompany.GetQuarterlyCompanyValue(company, AICompany.CURRENT_QUARTER); +} + +AITown.GetLastMonthTransported <- AITown.GetLastMonthSupplied; + +AIEvent.AI_ET_INVALID <- AIEvent.ET_INVALID; +AIEvent.AI_ET_TEST <- AIEvent.ET_TEST; +AIEvent.AI_ET_SUBSIDY_OFFER <- AIEvent.ET_SUBSIDY_OFFER; +AIEvent.AI_ET_SUBSIDY_OFFER_EXPIRED <- AIEvent.ET_SUBSIDY_OFFER_EXPIRED; +AIEvent.AI_ET_SUBSIDY_AWARDED <- AIEvent.ET_SUBSIDY_AWARDED; +AIEvent.AI_ET_SUBSIDY_EXPIRED <- AIEvent.ET_SUBSIDY_EXPIRED; +AIEvent.AI_ET_ENGINE_PREVIEW <- AIEvent.ET_ENGINE_PREVIEW; +AIEvent.AI_ET_COMPANY_NEW <- AIEvent.ET_COMPANY_NEW; +AIEvent.AI_ET_COMPANY_IN_TROUBLE <- AIEvent.ET_COMPANY_IN_TROUBLE; +AIEvent.AI_ET_COMPANY_ASK_MERGER <- AIEvent.ET_COMPANY_ASK_MERGER; +AIEvent.AI_ET_COMPANY_MERGER <- AIEvent.ET_COMPANY_MERGER; +AIEvent.AI_ET_COMPANY_BANKRUPT <- AIEvent.ET_COMPANY_BANKRUPT; +AIEvent.AI_ET_VEHICLE_CRASHED <- AIEvent.ET_VEHICLE_CRASHED; +AIEvent.AI_ET_VEHICLE_LOST <- AIEvent.ET_VEHICLE_LOST; +AIEvent.AI_ET_VEHICLE_WAITING_IN_DEPOT <- AIEvent.ET_VEHICLE_WAITING_IN_DEPOT; +AIEvent.AI_ET_VEHICLE_UNPROFITABLE <- AIEvent.ET_VEHICLE_UNPROFITABLE; +AIEvent.AI_ET_INDUSTRY_OPEN <- AIEvent.ET_INDUSTRY_OPEN; +AIEvent.AI_ET_INDUSTRY_CLOSE <- AIEvent.ET_INDUSTRY_CLOSE; +AIEvent.AI_ET_ENGINE_AVAILABLE <- AIEvent.ET_ENGINE_AVAILABLE; +AIEvent.AI_ET_STATION_FIRST_VEHICLE <- AIEvent.ET_STATION_FIRST_VEHICLE; +AIEvent.AI_ET_DISASTER_ZEPPELINER_CRASHED <- AIEvent.ET_DISASTER_ZEPPELINER_CRASHED; +AIEvent.AI_ET_DISASTER_ZEPPELINER_CLEARED <- AIEvent.ET_DISASTER_ZEPPELINER_CLEARED; +AIEvent.AI_ET_TOWN_FOUNDED <- AIEvent.ET_TOWN_FOUNDED; +AIOrder.AIOF_NONE <- AIOrder.OF_NONE +AIOrder.AIOF_NON_STOP_INTERMEDIATE <- AIOrder.OF_NON_STOP_INTERMEDIATE +AIOrder.AIOF_NON_STOP_DESTINATION <- AIOrder.OF_NON_STOP_DESTINATION +AIOrder.AIOF_UNLOAD <- AIOrder.OF_UNLOAD +AIOrder.AIOF_TRANSFER <- AIOrder.OF_TRANSFER +AIOrder.AIOF_NO_UNLOAD <- AIOrder.OF_NO_UNLOAD +AIOrder.AIOF_FULL_LOAD <- AIOrder.OF_FULL_LOAD +AIOrder.AIOF_FULL_LOAD_ANY <- AIOrder.OF_FULL_LOAD_ANY +AIOrder.AIOF_NO_LOAD <- AIOrder.OF_NO_LOAD +AIOrder.AIOF_SERVICE_IF_NEEDED <- AIOrder.OF_SERVICE_IF_NEEDED +AIOrder.AIOF_STOP_IN_DEPOT <- AIOrder.OF_STOP_IN_DEPOT +AIOrder.AIOF_GOTO_NEAREST_DEPOT <- AIOrder.OF_GOTO_NEAREST_DEPOT +AIOrder.AIOF_NON_STOP_FLAGS <- AIOrder.OF_NON_STOP_FLAGS +AIOrder.AIOF_UNLOAD_FLAGS <- AIOrder.OF_UNLOAD_FLAGS +AIOrder.AIOF_LOAD_FLAGS <- AIOrder.OF_LOAD_FLAGS +AIOrder.AIOF_DEPOT_FLAGS <- AIOrder.OF_DEPOT_FLAGS +AIOrder.AIOF_INVALID <- AIOrder.OF_INVALID diff --git a/bin/ai/compat_1.2.nut b/bin/ai/compat_1.2.nut new file mode 100644 index 0000000..0082415 --- /dev/null +++ b/bin/ai/compat_1.2.nut @@ -0,0 +1,10 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +AILog.Info("1.2 API compatibility in effect."); diff --git a/bin/ai/compat_1.3.nut b/bin/ai/compat_1.3.nut new file mode 100644 index 0000000..036f3b5 --- /dev/null +++ b/bin/ai/compat_1.3.nut @@ -0,0 +1,10 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +AILog.Info("1.3 API compatibility in effect."); diff --git a/bin/ai/compat_1.4.nut b/bin/ai/compat_1.4.nut new file mode 100644 index 0000000..3829bcc --- /dev/null +++ b/bin/ai/compat_1.4.nut @@ -0,0 +1,10 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +AILog.Info("1.4 API compatibility in effect."); diff --git a/bin/ai/compat_1.5.nut b/bin/ai/compat_1.5.nut new file mode 100644 index 0000000..fe985b9 --- /dev/null +++ b/bin/ai/compat_1.5.nut @@ -0,0 +1,8 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ diff --git a/bin/ai/regression/completeness.sh b/bin/ai/regression/completeness.sh new file mode 100755 index 0000000..9f5e96e --- /dev/null +++ b/bin/ai/regression/completeness.sh @@ -0,0 +1,69 @@ +#!/bin/sh + +# $Id$ + +if ! [ -f ai/regression/completeness.sh ]; then + echo "Make sure you are in the root of OpenTTD before starting this script." + exit 1 +fi + +cat ai/regression/tst_*/main.nut | tr ';' '\n' | awk ' +/^function/ { + for (local in locals) { + delete locals[local] + } + if (match($0, "function Regression::Start") || match($0, "function Regression::Stop")) next + locals["this"] = "AIControllerSquirrel" +} + +/local/ { + gsub(".*local", "local") + if (match($4, "^AI")) { + sub("\\(.*", "", $4) + locals[$2] = $4 + } +} + +/Valuate/ { + gsub(".*Valuate\\(", "") + gsub("\\).*", "") + gsub(",.*", "") + gsub("\\.", "::") + print $0 +} + +/\./ { + for (local in locals) { + if (match($0, local ".")) { + fname = substr($0, index($0, local ".")) + sub("\\(.*", "", fname) + sub("\\.", "::", fname) + sub(local, locals[local], fname) + print fname + if (match(locals[local], "List")) { + sub(locals[local], "AIAbstractList", fname) + print fname + } + } + } + # We want to remove everything before the FIRST occurence of AI. + # If we do not remove any other occurences of AI from the string + # we will remove everything before the LAST occurence of AI, so + # do some little magic to make it work the way we want. + sub("AI", "AXXXXY") + gsub("AI", "AXXXXX") + sub(".*AXXXXY", "AI") + if (match($0, "^AI") && match($0, ".")) { + sub("\\(.*", "", $0) + sub("\\.", "::", $0) + print $0 + } +} +' | sed 's/ //g' | sort | uniq > tmp.in_regression + +grep 'DefSQ.*Method' ../src/script/api/ai/*.hpp.sq | grep -v 'AIError::' | grep -v 'AIAbstractList::Valuate' | grep -v '::GetClassName' | sed 's/^[^,]*, &//g;s/,[^,]*//g' | sort > tmp.in_api + +diff -u tmp.in_regression tmp.in_api | grep -v '^+++' | grep '^+' | sed 's/^+//' + +rm -f tmp.in_regression tmp.in_api + diff --git a/bin/ai/regression/empty.sav b/bin/ai/regression/empty.sav new file mode 100644 index 0000000..cf97052 Binary files /dev/null and b/bin/ai/regression/empty.sav differ diff --git a/bin/ai/regression/regression.cfg b/bin/ai/regression/regression.cfg new file mode 100644 index 0000000..4b8a5f6 --- /dev/null +++ b/bin/ai/regression/regression.cfg @@ -0,0 +1,20 @@ +[misc] +display_opt = SHOW_TOWN_NAMES|SHOW_STATION_NAMES|SHOW_SIGNS|WAYPOINTS +language = english.lng + +[gui] +autosave = off + +[game_creation] +town_name = english + +[ai_players] +none = +regression = + +[vehicle] +road_side = right +plane_speed = 2 + +[construction] +max_bridge_length = 100 diff --git a/bin/ai/regression/regression_info.nut b/bin/ai/regression/regression_info.nut new file mode 100644 index 0000000..86f4484 --- /dev/null +++ b/bin/ai/regression/regression_info.nut @@ -0,0 +1,15 @@ +/* $Id$ */ + +class Regression extends AIInfo { + function GetAuthor() { return "OpenTTD NoAI Developers Team"; } + function GetName() { return "Regression"; } + function GetShortName() { return "REGR"; } + function GetDescription() { return "This runs regression-tests on some commands. On the same map the result should always be the same."; } + function GetVersion() { return 1; } + function GetAPIVersion() { return "1.5"; } + function GetDate() { return "2007-03-18"; } + function CreateInstance() { return "Regression"; } +} + +RegisterAI(Regression()); + diff --git a/bin/ai/regression/run.sh b/bin/ai/regression/run.sh new file mode 100755 index 0000000..d47a664 --- /dev/null +++ b/bin/ai/regression/run.sh @@ -0,0 +1,71 @@ +#!/bin/sh + +# $Id$ + +if ! [ -f ai/regression/run.sh ]; then + echo "Make sure you are in the root of OpenTTD before starting this script." + exit 1 +fi + +if [ -f scripts/game_start.scr ]; then + mv scripts/game_start.scr scripts/game_start.scr.regression +fi + +params="" +gdb="" +if [ "$1" != "-r" ]; then + params="-snull -mnull -vnull:ticks=30000" +fi +if [ "$1" = "-g" ]; then + gdb="gdb --ex run --args " +fi + +if [ -d "ai/regression/tst_$1" ]; then + tests="ai/regression/tst_$1" +elif [ -d "ai/regression/tst_$2" ]; then + tests="ai/regression/tst_$2" +else + tests=ai/regression/tst_* +fi + +ret=0 +for tst in $tests; do + echo -n "Running $tst... " + + # Make sure that only one info.nut is present for each test run. Otherwise openttd gets confused. + cp ai/regression/regression_info.nut $tst/info.nut + + sav=$tst/test.sav + if ! [ -f $sav ]; then + sav=ai/regression/empty.sav + fi + + if [ -n "$gdb" ]; then + $gdb ./openttd -x -c ai/regression/regression.cfg $params -g $sav + else + ./openttd -x -c ai/regression/regression.cfg $params -g $sav -d script=2 -d misc=9 2>&1 | awk '{ gsub("0x(\\(nil\\)|0+)(x0)?", "0x00000000", $0); gsub("^dbg: \\[script\\]", "", $0); gsub("^ ", "ERROR: ", $0); gsub("ERROR: \\[1\\] ", "", $0); gsub("\\[P\\] ", "", $0); print $0; }' | grep -v '^dbg: \[.*\]' > tmp.regression + fi + + if [ -z "$gdb" ]; then + res="`diff -ub $tst/result.txt tmp.regression`" + if [ -z "$res" ]; then + echo "passed!" + else + echo "failed! Difference:" + echo "$res" + ret=1 + fi + fi + + rm $tst/info.nut +done + +if [ -f scripts/game_start.scr.regression ]; then + mv scripts/game_start.scr.regression scripts/game_start.scr +fi + +if [ "$1" != "-k" ]; then + rm -f tmp.regression +fi + +exit $ret diff --git a/bin/ai/regression/tst_regression/main.nut b/bin/ai/regression/tst_regression/main.nut new file mode 100644 index 0000000..f575f53 --- /dev/null +++ b/bin/ai/regression/tst_regression/main.nut @@ -0,0 +1,1863 @@ +/* $Id$ */ + +class Regression extends AIController { + function Start(); +}; + + + +function Regression::TestInit() +{ + print(""); + print("--TestInit--"); + print(" Ops: " + this.GetOpsTillSuspend()); + print(" TickTest: " + this.GetTick()); + this.Sleep(1); + print(" TickTest: " + this.GetTick()); + print(" Ops: " + this.GetOpsTillSuspend()); + print(" SetCommandDelay: " + AIController.SetCommandDelay(1)); + print(" IsValid(vehicle.plane_speed): " + AIGameSettings.IsValid("vehicle.plane_speed")); + print(" vehicle.plane_speed: " + AIGameSettings.GetValue("vehicle.plane_speed")); + require("require.nut"); + print(" min(6, 3): " + min(6, 3)); + print(" min(3, 6): " + min(3, 6)); + print(" max(6, 3): " + max(6, 3)); + print(" max(3, 6): " + max(3, 6)); + + print(" AIList Consistency Tests"); + print(""); + print(" Value Descending"); + local list = AIList(); + list.AddItem( 5, 10); + list.AddItem(10, 10); + list.AddItem(15, 20); + list.AddItem(20, 20); + list.AddItem(25, 30); + list.AddItem(30, 30); + list.AddItem(35, 40); + list.AddItem(40, 40); + + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + list.RemoveItem(i - 10); + list.RemoveItem(i - 5); + list.RemoveItem(i); + print(" " + i); + } + + list.AddItem(10, 10); + list.AddItem(20, 20); + list.AddItem(30, 30); + list.AddItem(40, 40); + + print(""); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + list.SetValue(i, 2); + print(" " + i); + } + print(""); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i); + } + + list = AIList(); + list.Sort(AIList.SORT_BY_VALUE, AIList.SORT_ASCENDING); + print(""); + print(" Value Ascending"); + list.AddItem( 5, 10); + list.AddItem(10, 10); + list.AddItem(15, 20); + list.AddItem(20, 20); + list.AddItem(25, 30); + list.AddItem(30, 30); + list.AddItem(35, 40); + list.AddItem(40, 40); + + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + list.RemoveItem(i + 10); + list.RemoveItem(i + 5); + list.RemoveItem(i); + print(" " + i); + } + + list.AddItem(10, 10); + list.AddItem(20, 20); + list.AddItem(30, 30); + list.AddItem(40, 40); + + print(""); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + list.SetValue(i, 50); + print(" " + i); + } + print(""); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i); + } + + list = AIList(); + list.Sort(AIList.SORT_BY_ITEM, AIList.SORT_DESCENDING); + print(""); + print(" Item Descending"); + list.AddItem( 5, 10); + list.AddItem(10, 10); + list.AddItem(15, 20); + list.AddItem(20, 20); + list.AddItem(25, 30); + list.AddItem(30, 30); + list.AddItem(35, 40); + list.AddItem(40, 40); + + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + list.RemoveItem(i - 10); + list.RemoveItem(i - 5); + list.RemoveItem(i); + print(" " + i); + } + + list.AddItem(10, 10); + list.AddItem(20, 20); + list.AddItem(30, 30); + list.AddItem(40, 40); + + print(""); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + list.SetValue(i, 2); + print(" " + i); + } + print(""); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i); + } + + list = AIList(); + list.Sort(AIList.SORT_BY_ITEM, AIList.SORT_ASCENDING); + print(""); + print(" Item Ascending"); + list.AddItem( 5, 10); + list.AddItem(10, 10); + list.AddItem(15, 20); + list.AddItem(20, 20); + list.AddItem(25, 30); + list.AddItem(30, 30); + list.AddItem(35, 40); + list.AddItem(40, 40); + + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + list.RemoveItem(i + 10); + list.RemoveItem(i + 5); + list.RemoveItem(i); + print(" " + i); + } + + list.AddItem(10, 10); + list.AddItem(20, 20); + list.AddItem(30, 30); + list.AddItem(40, 40); + + print(""); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + list.SetValue(i, 50); + print(" " + i); + } + print(""); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i); + } + + list.Clear(); + foreach (idx, val in list) { + print(" " + idx); + } + + print(" Ops: " + this.GetOpsTillSuspend()); +} + +function Regression::Std() +{ + print(""); + print("--Std--"); + print(" abs(-21): " + abs(-21)); + print(" abs( 21): " + abs(21)); +} + +function Regression::Base() +{ + print(""); + print("--AIBase--"); + print(" Rand(): " + AIBase.Rand()); + print(" Rand(): " + AIBase.Rand()); + print(" Rand(): " + AIBase.Rand()); + print(" RandRange(0): " + AIBase.RandRange(0)); + print(" RandRange(0): " + AIBase.RandRange(0)); + print(" RandRange(0): " + AIBase.RandRange(0)); + print(" RandRange(1): " + AIBase.RandRange(1)); + print(" RandRange(1): " + AIBase.RandRange(1)); + print(" RandRange(1): " + AIBase.RandRange(1)); + print(" RandRange(2): " + AIBase.RandRange(2)); + print(" RandRange(2): " + AIBase.RandRange(2)); + print(" RandRange(2): " + AIBase.RandRange(2)); + print(" RandRange(1000000): " + AIBase.RandRange(1000000)); // 32 bit tests + print(" RandRange(1000000): " + AIBase.RandRange(1000000)); + print(" RandRange(1000000): " + AIBase.RandRange(1000000)); + print(" Chance(1, 2): " + AIBase.Chance(1, 2)); + print(" Chance(1, 2): " + AIBase.Chance(1, 2)); + print(" Chance(1, 2): " + AIBase.Chance(1, 2)); + + AIRoad.SetCurrentRoadType(AIRoad.ROADTYPE_ROAD); +} + +function Regression::Airport() +{ + print(""); + print("--AIAirport--"); + + print(" IsHangarTile(): " + AIAirport.IsHangarTile(32116)); + print(" IsAirportTile(): " + AIAirport.IsAirportTile(32116)); + print(" GetHangarOfAirport(): " + AIAirport.GetHangarOfAirport(32116)); + print(" GetAirportType(): " + AIAirport.GetAirportType(32116)); + + for (local i = -1; i < 10; i++) { + print(" IsAirportInformationAvailable(" + i + "): " + AIAirport.IsAirportInformationAvailable(i)); + print(" IsValidAirportType(" + i + "): " + AIAirport.IsValidAirportType(i)); + print(" GetAirportWidth(" + i + "): " + AIAirport.GetAirportWidth(i)); + print(" GetAirportHeight(" + i + "): " + AIAirport.GetAirportHeight(i)); + print(" GetAirportCoverageRadius(" + i + "): " + AIAirport.GetAirportCoverageRadius(i)); + } + + print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF)); + print(" GetPrice(): " + AIAirport.GetPrice(0)); + print(" BuildAirport(): " + AIAirport.BuildAirport(32116, 0, AIStation.STATION_JOIN_ADJACENT)); + print(" IsHangarTile(): " + AIAirport.IsHangarTile(32116)); + print(" IsAirportTile(): " + AIAirport.IsAirportTile(32116)); + print(" GetAirportType(): " + AIAirport.GetAirportType(32119)); + print(" GetHangarOfAirport(): " + AIAirport.GetHangarOfAirport(32116)); + print(" IsHangarTile(): " + AIAirport.IsHangarTile(32119)); + print(" IsAirportTile(): " + AIAirport.IsAirportTile(32119)); + print(" GetAirportType(): " + AIAirport.GetAirportType(32119)); + print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF)); + + print(" RemoveAirport(): " + AIAirport.RemoveAirport(32118)); + print(" IsHangarTile(): " + AIAirport.IsHangarTile(32119)); + print(" IsAirportTile(): " + AIAirport.IsAirportTile(32119)); + print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF)); + print(" BuildAirport(): " + AIAirport.BuildAirport(32116, 0, AIStation.STATION_JOIN_ADJACENT)); +} + +function Regression::Bridge() +{ + local j = 0; + + print(""); + print("--Bridge--"); + for (local i = -1; i < 14; i++) { + if (AIBridge.IsValidBridge(i)) j++; + print(" Bridge " + i); + print(" IsValidBridge(): " + AIBridge.IsValidBridge(i)); + print(" GetName(): " + AIBridge.GetName(i)); + print(" GetMaxSpeed(): " + AIBridge.GetMaxSpeed(i)); + print(" GetPrice(): " + AIBridge.GetPrice(i, 5)); + print(" GetMaxLength(): " + AIBridge.GetMaxLength(i)); + print(" GetMinLength(): " + AIBridge.GetMinLength(i)); + } + print(" Valid Bridges: " + j); + + print(" IsBridgeTile(): " + AIBridge.IsBridgeTile(33160)); + print(" GetBridgeID(): " + AIBridge.GetBridgeID(33160)); + print(" RemoveBridge(): " + AIBridge.RemoveBridge(33155)); + print(" GetLastErrorString(): " + AIError.GetLastErrorString()); + print(" GetOtherBridgeEnd(): " + AIBridge.GetOtherBridgeEnd(33160)); + print(" BuildBridge(): " + AIBridge.BuildBridge(AIVehicle.VT_ROAD, 5, 33160, 33155)); + print(" IsBridgeTile(): " + AIBridge.IsBridgeTile(33160)); + print(" GetBridgeID(): " + AIBridge.GetBridgeID(33160)); + print(" IsBridgeTile(): " + AIBridge.IsBridgeTile(33155)); + print(" GetBridgeID(): " + AIBridge.GetBridgeID(33155)); + print(" GetOtherBridgeEnd(): " + AIBridge.GetOtherBridgeEnd(33160)); + print(" BuildBridge(): " + AIBridge.BuildBridge(AIVehicle.VT_ROAD, 5, 33160, 33155)); + print(" GetLastErrorString(): " + AIError.GetLastErrorString()); + print(" RemoveBridge(): " + AIBridge.RemoveBridge(33155)); + print(" IsBridgeTile(): " + AIBridge.IsBridgeTile(33160)); +} + +function Regression::BridgeList() +{ + local list = AIBridgeList(); + + print(""); + print("--BridgeList--"); + print(" Count(): " + list.Count()); + list.Valuate(AIBridge.GetMaxSpeed); + print(" MaxSpeed ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIBridge.GetPrice, 5); + print(" Price ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIBridge.GetMaxLength); + print(" MaxLength ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIBridge.GetMinLength); + print(" MinLength ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + + list = AIBridgeList_Length(14); + + print(""); + print("--BridgeList_Length--"); + print(" Count(): " + list.Count()); + list.Valuate(AIBridge.GetMaxSpeed); + print(" MaxSpeed ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIBridge.GetPrice, 14); + print(" Price ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } +} + +function Regression::Cargo() +{ + print(""); + print("--AICargo--"); + for (local i = -1; i < 15; i++) { + print(" Cargo " + i); + print(" IsValidCargo(): " + AICargo.IsValidCargo(i)); + print(" GetCargoLabel(): '" + AICargo.GetCargoLabel(i)+ "'"); + print(" IsFreight(): " + AICargo.IsFreight(i)); + print(" HasCargoClass(): " + AICargo.HasCargoClass(i, AICargo.CC_PASSENGERS)); + print(" GetTownEffect(): " + AICargo.GetTownEffect(i)); + print(" GetCargoIncome(0, 0): " + AICargo.GetCargoIncome(i, 0, 0)); + print(" GetCargoIncome(10, 10): " + AICargo.GetCargoIncome(i, 10, 10)); + print(" GetCargoIncome(100, 10): " + AICargo.GetCargoIncome(i, 100, 10)); + print(" GetCargoIncome(10, 100): " + AICargo.GetCargoIncome(i, 10, 100)); + print(" GetRoadVehicleTypeForCargo(): " + AIRoad.GetRoadVehicleTypeForCargo(i)); + } +} + +function Regression::CargoList() +{ + local list = AICargoList(); + + print(""); + print("--CargoList--"); + print(" Count(): " + list.Count()); + list.Valuate(AICargo.IsFreight); + print(" IsFreight ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + + list.Valuate(AICargo.GetCargoIncome, 100, 100); + print(" CargoIncomes(100, 100) ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + + list = AICargoList_IndustryAccepting(8); + print(""); + print("--CargoList_IndustryAccepting--"); + print(" Count(): " + list.Count()); + print(" ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i); + } + + list = AICargoList_IndustryProducing(4); + print(""); + print("--CargoList_IndustryProducing--"); + print(" Count(): " + list.Count()); + print(" ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i); + } +} + +function Regression::Company() +{ + print(""); + print("--Company--"); + + /* Test AIXXXMode() in scopes */ + { + local test = AITestMode(); + print(" SetName(): " + AICompany.SetName("Regression")); + print(" SetName(): " + AICompany.SetName("Regression")); + { + local exec = AIExecMode(); + print(" SetName(): " + AICompany.SetName("Regression")); + print(" SetName(): " + AICompany.SetName("Regression")); + print(" GetLastErrorString(): " + AIError.GetLastErrorString()); + } + } + + print(" GetName(): " + AICompany.GetName(AICompany.COMPANY_SELF)); + print(" GetPresidentName(): " + AICompany.GetPresidentName(AICompany.COMPANY_SELF)); + print(" SetPresidentName(): " + AICompany.SetPresidentName("Regression AI")); + print(" GetPresidentName(): " + AICompany.GetPresidentName(AICompany.COMPANY_SELF)); + print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF)); + print(" GetName(): " + AICompany.GetName(240)); + print(" GetLoanAmount(): " + AICompany.GetLoanAmount()); + print(" GetMaxLoanAmount(): " + AICompany.GetMaxLoanAmount()); + print(" GetLoanInterval(): " + AICompany.GetLoanInterval()); + print(" SetLoanAmount(1): " + AICompany.SetLoanAmount(1)); + print(" SetLoanAmount(100): " + AICompany.SetLoanAmount(100)); + print(" SetLoanAmount(10000): " + AICompany.SetLoanAmount(10000)); + print(" GetLastErrorString(): " + AIError.GetLastErrorString()); + print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF)); + print(" GetLoanAmount(): " + AICompany.GetLoanAmount()); + print(" SetMinimumLoanAmount(31337): " + AICompany.SetMinimumLoanAmount(31337)); + print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF)); + print(" GetLoanAmount(): " + AICompany.GetLoanAmount()); + print(" SetLoanAmount(10000): " + AICompany.SetLoanAmount(AICompany.GetMaxLoanAmount())); + print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF)); + print(" GetLoanAmount(): " + AICompany.GetLoanAmount()); + print(" GetCompanyHQ(): " + AICompany.GetCompanyHQ(AICompany.COMPANY_SELF)); + print(" BuildCompanyHQ(): " + AICompany.BuildCompanyHQ(AIMap.GetTileIndex(127, 129))); + print(" GetCompanyHQ(): " + AICompany.GetCompanyHQ(AICompany.COMPANY_SELF)); + print(" BuildCompanyHQ(): " + AICompany.BuildCompanyHQ(AIMap.GetTileIndex(129, 129))); + print(" GetCompanyHQ(): " + AICompany.GetCompanyHQ(AICompany.COMPANY_SELF)); + print(" BuildCompanyHQ(): " + AICompany.BuildCompanyHQ(AIMap.GetTileIndex(129, 128))); + print(" GetLastErrorString(): " + AIError.GetLastErrorString()); + print(" GetAutoRenewStatus(); " + AICompany.GetAutoRenewStatus(AICompany.COMPANY_SELF)); + print(" SetAutoRenewStatus(true); " + AICompany.SetAutoRenewStatus(true)); + print(" GetAutoRenewStatus(); " + AICompany.GetAutoRenewStatus(AICompany.COMPANY_SELF)); + print(" SetAutoRenewStatus(true); " + AICompany.SetAutoRenewStatus(true)); + print(" SetAutoRenewStatus(false); " + AICompany.SetAutoRenewStatus(false)); + print(" GetAutoRenewMonths(); " + AICompany.GetAutoRenewMonths(AICompany.COMPANY_SELF)); + print(" SetAutoRenewMonths(-12); " + AICompany.SetAutoRenewMonths(-12)); + print(" GetAutoRenewMonths(); " + AICompany.GetAutoRenewMonths(AICompany.COMPANY_SELF)); + print(" SetAutoRenewMonths(-12); " + AICompany.SetAutoRenewMonths(-12)); + print(" SetAutoRenewMonths(6); " + AICompany.SetAutoRenewMonths(6)); + print(" GetAutoRenewMoney(); " + AICompany.GetAutoRenewMoney(AICompany.COMPANY_SELF)); + print(" SetAutoRenewMoney(200000); " + AICompany.SetAutoRenewMoney(200000)); + print(" GetAutoRenewMoney(); " + AICompany.GetAutoRenewMoney(AICompany.COMPANY_SELF)); + print(" SetAutoRenewMoney(200000); " + AICompany.SetAutoRenewMoney(200000)); + print(" SetAutoRenewMoney(100000); " + AICompany.SetAutoRenewMoney(100000)); + for (local i = -1; i <= AICompany.EARLIEST_QUARTER; i++) { + print(" Quarter: " + i); + print(" GetQuarterlyIncome(); " + AICompany.GetQuarterlyIncome(AICompany.COMPANY_SELF, i)); + print(" GetQuarterlyExpenses(); " + AICompany.GetQuarterlyExpenses(AICompany.COMPANY_SELF, i)); + print(" GetQuarterlyCargoDelivered(); " + AICompany.GetQuarterlyCargoDelivered(AICompany.COMPANY_SELF, i)); + print(" GetQuarterlyPerformanceRating(); " + AICompany.GetQuarterlyPerformanceRating(AICompany.COMPANY_SELF, i)); + print(" GetQuarterlyCompanyValue(); " + AICompany.GetQuarterlyCompanyValue(AICompany.COMPANY_SELF, i)); + } +} + +function Regression::Engine() +{ + local j = 0; + + print(""); + print("--Engine--"); + for (local i = -1; i < 257; i++) { + if (AIEngine.IsValidEngine(i)) j++; + print(" Engine " + i); + print(" IsValidEngine(): " + AIEngine.IsValidEngine(i)); + print(" GetName(): " + AIEngine.GetName(i)); + print(" GetCargoType(): " + AIEngine.GetCargoType(i)); + print(" CanRefitCargo(): " + AIEngine.CanRefitCargo(i, 1)); + print(" GetCapacity(): " + AIEngine.GetCapacity(i)); + print(" GetReliability(): " + AIEngine.GetReliability(i)); + print(" GetMaxSpeed(): " + AIEngine.GetMaxSpeed(i)); + print(" GetPrice(): " + AIEngine.GetPrice(i)); + print(" GetMaxAge(): " + AIEngine.GetMaxAge(i)); + print(" GetRunningCost(): " + AIEngine.GetRunningCost(i)); + print(" GetPower(): " + AIEngine.GetPower(i)); + print(" GetWeight(): " + AIEngine.GetWeight(i)); + print(" GetMaxTractiveEffort(): " + AIEngine.GetMaxTractiveEffort(i)); + print(" GetVehicleType(): " + AIEngine.GetVehicleType(i)); + print(" GetRailType(): " + AIEngine.GetRailType(i)); + print(" GetRoadType(): " + AIEngine.GetRoadType(i)); + print(" GetPlaneType(): " + AIEngine.GetPlaneType(i)); + } + print(" Valid Engines: " + j); +} + +function Regression::EngineList() +{ + local list = AIEngineList(AIVehicle.VT_ROAD); + + print(""); + print("--EngineList--"); + print(" Count(): " + list.Count()); + list.Valuate(AIEngine.GetCargoType); + print(" CargoType ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIEngine.GetCapacity); + print(" Capacity ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIEngine.GetReliability); + print(" Reliability ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIEngine.GetMaxSpeed); + print(" MaxSpeed ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIEngine.GetPrice); + print(" Price ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } +} + +function Regression::Prices() +{ + print(""); + print("--Prices--"); + print(" -Rail-"); + print(" 0,BT_TRACK: " + AIRail.GetBuildCost(0, AIRail.BT_TRACK)); + print(" 0,BT_SIGNAL: " + AIRail.GetBuildCost(0, AIRail.BT_SIGNAL)); + print(" 0,BT_DEPOT: " + AIRail.GetBuildCost(0, AIRail.BT_DEPOT)); + print(" 0,BT_STATION: " + AIRail.GetBuildCost(0, AIRail.BT_STATION)); + print(" 0,BT_WAYPOINT: " + AIRail.GetBuildCost(0, AIRail.BT_WAYPOINT)); + print(" 1,BT_TRACK: " + AIRail.GetBuildCost(1, AIRail.BT_TRACK)); + print(" 1,BT_SIGNAL: " + AIRail.GetBuildCost(1, AIRail.BT_SIGNAL)); + print(" 1,BT_DEPOT: " + AIRail.GetBuildCost(1, AIRail.BT_DEPOT)); + print(" 1,BT_STATION: " + AIRail.GetBuildCost(1, AIRail.BT_STATION)); + print(" 1,BT_WAYPOINT: " + AIRail.GetBuildCost(1, AIRail.BT_WAYPOINT)); + print(" -Road-"); + print(" ROADTYPE_ROAD,BT_ROAD: " + AIRoad.GetBuildCost(AIRoad.ROADTYPE_ROAD, AIRoad.BT_ROAD)); + print(" ROADTYPE_ROAD,BT_DEPOT: " + AIRoad.GetBuildCost(AIRoad.ROADTYPE_ROAD, AIRoad.BT_DEPOT)); + print(" ROADTYPE_ROAD,BT_BUS_STOP: " + AIRoad.GetBuildCost(AIRoad.ROADTYPE_ROAD, AIRoad.BT_BUS_STOP)); + print(" ROADTYPE_ROAD,BT_TRUCK_STOP: " + AIRoad.GetBuildCost(AIRoad.ROADTYPE_ROAD, AIRoad.BT_TRUCK_STOP)); + print(" ROADTYPE_TRAM,BT_ROAD: " + AIRoad.GetBuildCost(AIRoad.ROADTYPE_TRAM, AIRoad.BT_ROAD)); + print(" ROADTYPE_TRAM,BT_DEPOT: " + AIRoad.GetBuildCost(AIRoad.ROADTYPE_TRAM, AIRoad.BT_DEPOT)); + print(" ROADTYPE_TRAM,BT_BUS_STOP: " + AIRoad.GetBuildCost(AIRoad.ROADTYPE_TRAM, AIRoad.BT_BUS_STOP)); + print(" ROADTYPE_TRAM,BT_TRUCK_STOP: " + AIRoad.GetBuildCost(AIRoad.ROADTYPE_TRAM, AIRoad.BT_TRUCK_STOP)); + print(" -Water-"); + print(" BT_DOCK: " + AIMarine.GetBuildCost(AIMarine.BT_DOCK)); + print(" BT_DEPOT: " + AIMarine.GetBuildCost(AIMarine.BT_DEPOT)); + print(" BT_BUOY: " + AIMarine.GetBuildCost(AIMarine.BT_BUOY)); + print(" -Tile-"); + print(" BT_FOUNDATION: " + AITile.GetBuildCost(AITile.BT_FOUNDATION)); + print(" BT_TERRAFORM: " + AITile.GetBuildCost(AITile.BT_TERRAFORM)); + print(" BT_BUILD_TREES: " + AITile.GetBuildCost(AITile.BT_BUILD_TREES)); + print(" BT_CLEAR_GRASS: " + AITile.GetBuildCost(AITile.BT_CLEAR_GRASS)); + print(" BT_CLEAR_ROUGH: " + AITile.GetBuildCost(AITile.BT_CLEAR_ROUGH)); + print(" BT_CLEAR_ROCKY: " + AITile.GetBuildCost(AITile.BT_CLEAR_ROCKY)); + print(" BT_CLEAR_FIELDS: " + AITile.GetBuildCost(AITile.BT_CLEAR_FIELDS)); + print(" BT_CLEAR_HOUSE: " + AITile.GetBuildCost(AITile.BT_CLEAR_HOUSE)); +} + +function cost_callback(old_path, new_tile, new_direction, self) { if (old_path == null) return 0; return old_path.GetCost() + 1; } +function estimate_callback(tile, direction, goals, self) { return goals[0] - tile; } +function neighbours_callback(path, cur_tile, self) { return [[cur_tile + 1, 1]]; } +function check_direction_callback(tile, existing_direction, new_direction, self) { return false; } + +function Regression::Group() +{ + print (""); + print("--Group--"); + print(" SetAutoReplace(): " + AIGroup.SetAutoReplace(AIGroup.GROUP_ALL, 116, 117)); + print(" GetEngineReplacement(): " + AIGroup.GetEngineReplacement(AIGroup.GROUP_ALL, 116)); + print(" GetNumEngines(): " + AIGroup.GetNumEngines(AIGroup.GROUP_ALL, 116)); + print(" AIRoad.BuildRoadDepot(): " + AIRoad.BuildRoadDepot(10000, 10001)); + local vehicle = AIVehicle.BuildVehicle(10000, 116); + print(" AIVehicle.BuildVehicle(): " + vehicle); + print(" GetNumEngines(): " + AIGroup.GetNumEngines(AIGroup.GROUP_ALL, 116)); + local group = AIGroup.CreateGroup(AIVehicle.VT_ROAD); + print(" CreateGroup(): " + group); + print(" MoveVehicle(): " + AIGroup.MoveVehicle(group, vehicle)); + print(" GetNumEngines(): " + AIGroup.GetNumEngines(group, 116)); + print(" GetNumEngines(): " + AIGroup.GetNumEngines(AIGroup.GROUP_ALL, 116)); + print(" GetNumEngines(): " + AIGroup.GetNumEngines(AIGroup.GROUP_DEFAULT, 116)); + print(" GetName(): " + AIGroup.GetName(0)); + print(" GetName(): " + AIGroup.GetName(1)); + print(" AIVehicle.SellVehicle(): " + AIVehicle.SellVehicle(vehicle)); + print(" AITile.DemolishTile(): " + AITile.DemolishTile(10000)); + print(" HasWagonRemoval(): " + AIGroup.HasWagonRemoval()); + print(" EnableWagonRemoval(): " + AIGroup.EnableWagonRemoval(true)); + print(" HasWagonRemoval(): " + AIGroup.HasWagonRemoval()); + print(" EnableWagonRemoval(): " + AIGroup.EnableWagonRemoval(false)); + print(" EnableWagonRemoval(): " + AIGroup.EnableWagonRemoval(false)); + print(" HasWagonRemoval(): " + AIGroup.HasWagonRemoval()); +} + +function Regression::Industry() +{ + local j = 0; + + print(""); + print("--Industry--"); + print(" GetIndustryCount(): " + AIIndustry.GetIndustryCount()); + local list = AIIndustryList(); + list.Sort(AIList.SORT_BY_ITEM, AIList.SORT_ASCENDING); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + if (AIIndustry.IsValidIndustry(i)) j++; + print(" Industry " + i); + print(" IsValidIndustry(): " + AIIndustry.IsValidIndustry(i)); + print(" GetName(): " + AIIndustry.GetName(i)); + print(" GetLocation(): " + AIIndustry.GetLocation(i)); + print(" IsCargoAccepted(): " + AIIndustry.IsCargoAccepted(i, 1)); + + local cargo_list = AICargoList(); + for (local j = cargo_list.Begin(); !cargo_list.IsEnd(); j = cargo_list.Next()) { + if (AIIndustry.IsCargoAccepted(i, j) || AIIndustry.GetLastMonthProduction(i,j) >= 0) { + print(" GetLastMonthProduction(): " + AIIndustry.GetLastMonthProduction(i, j)); + print(" GetLastMonthTransported(): " + AIIndustry.GetLastMonthTransported(i, j)); + print(" GetStockpiledCargo(): " + AIIndustry.GetStockpiledCargo(i, j)); + } + } + } + print(" Valid Industries: " + j); + print(" GetIndustryCount(): " + AIIndustry.GetIndustryCount()); + print(" GetIndustryID(): " + AIIndustry.GetIndustryID(19694)); + print(" GetIndustryID(): " + AIIndustry.GetIndustryID(19695)); +} + +function Regression::IndustryList() +{ + local list = AIIndustryList(); + + print(""); + print("--IndustryList--"); + print(" Count(): " + list.Count()); + list.Valuate(AIIndustry.GetLocation); + print(" Location ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIIndustry.GetDistanceManhattanToTile, 30000); + print(" DistanceManhattanToTile(30000) ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIIndustry.GetDistanceSquareToTile, 30000); + print(" DistanceSquareToTile(30000) ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIIndustry.GetAmountOfStationsAround); + print(" GetAmountOfStationsAround(30000) ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIIndustry.IsCargoAccepted, 1); + print(" CargoAccepted(1) ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + + list = AIIndustryList_CargoAccepting(1); + print("--IndustryList_CargoAccepting--"); + print(" Count(): " + list.Count()); + list.Valuate(AIIndustry.GetLocation); + print(" Location ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + + list = AIIndustryList_CargoProducing(1); + print("--IndustryList_CargoProducing--"); + print(" Count(): " + list.Count()); + list.Valuate(AIIndustry.GetLocation); + print(" Location ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } +} + +function Regression::IndustryTypeList() +{ + local list = AIIndustryTypeList(); + + print(""); + print("--IndustryTypeList--"); + print(" Count(): " + list.Count()); + list.Valuate(AIIndustry.GetLocation); + print(" Location ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" Id: " + i); + print(" IsRawIndustry(): " + AIIndustryType.IsRawIndustry(i)); + print(" ProductionCanIncrease(): " + AIIndustryType.ProductionCanIncrease(i)); + print(" GetConstructionCost(): " + AIIndustryType.GetConstructionCost(i)); + print(" GetName(): " + AIIndustryType.GetName(i)); + print(" CanBuildIndustry(): " + AIIndustryType.CanBuildIndustry(i)); + print(" CanProspectIndustry(): " + AIIndustryType.CanProspectIndustry(i)); + print(" IsBuiltOnWater(): " + AIIndustryType.IsBuiltOnWater(i)); + print(" HasHeliport(): " + AIIndustryType.HasHeliport(i)); + print(" HasDock(): " + AIIndustryType.HasDock(i)); + } +} + +function CustomValuator(list_id) +{ + return list_id * 4343; +} + +function Regression::List() +{ + local list = AIList(); + + print(""); + print("--List--"); + + print(" IsEmpty(): " + list.IsEmpty()); + list.AddItem(1, 1); + list.AddItem(2, 2); + for (local i = 1000; i < 1100; i++) { + list.AddItem(i, i); + } + list.RemoveItem(1050); + list.RemoveItem(1150); + list.SetValue(1051, 12); + print(" Count(): " + list.Count()); + print(" HasItem(1050): " + list.HasItem(1050)); + print(" HasItem(1051): " + list.HasItem(1051)); + print(" IsEmpty(): " + list.IsEmpty()); + list.Sort(AIList.SORT_BY_ITEM, AIList.SORT_ASCENDING); + print(" List Dump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(CustomValuator); + print(" Custom ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(function (a) { return a * 42; }); + print(" Custom ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIBase.RandItem); + print(" Randomize ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + + list.KeepTop(10); + print(" KeepTop(10):"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.KeepBottom(8); + print(" KeepBottom(8):"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.RemoveBottom(2); + print(" RemoveBottom(2):"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.RemoveTop(2); + print(" RemoveTop(2):"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + + local list2 = AIList(); + list2.AddItem(1003, 0); + list2.AddItem(1004, 0); + list.RemoveList(list2); + print(" RemoveList({1003, 1004}):"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list2.AddItem(1005, 0); + list.KeepList(list2); + print(" KeepList({1003, 1004, 1005}):"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list2.Clear(); + for (local i = 4000; i < 4003; i++) { + list2.AddItem(i, i * 2); + } + list2.AddItem(1005, 1005); + list.AddList(list2); + print(" AddList({1005, 4000, 4001, 4002}):"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list[4000] = 50; + list[4006] = 12; + + print(" foreach():"); + foreach (idx, val in list) { + print(" " + idx + " => " + val); + } + print(" []:"); + print(" 4000 => " + list[4000]); + + list.Clear(); + print(" IsEmpty(): " + list.IsEmpty()); + + for (local i = 0; i < 10; i++) { + list.AddItem(i, 5 + i / 2); + } + + local it = list.Begin(); + print(" " + it + " => " + list.GetValue(it) + " (" + !list.IsEnd() + ")"); + list.Sort(list.SORT_BY_VALUE, list.SORT_ASCENDING); + it = list.Next(); + print(" " + it + " => " + list.GetValue(it) + " (" + !list.IsEnd() + ")"); + + it = list.Begin(); + print(" " + it + " => " + list.GetValue(it) + " (" + !list.IsEnd() + ")"); + + list.SetValue(it + 1, -5); + it = list.Next(); + print(" " + it + " => " + list.GetValue(it) + " (" + !list.IsEnd() + ")"); + + list.RemoveValue(list.GetValue(it) + 1); + it = list.Next(); + print(" " + it + " => " + list.GetValue(it) + " (" + !list.IsEnd() + ")"); + + list.RemoveAboveValue(list.GetValue(it)); + it = list.Next(); + print(" " + it + " => " + list.GetValue(it) + " (" + !list.IsEnd() + ")"); + + while (!list.IsEnd()) { + it = list.Next(); + print(" " + it + " => " + list.GetValue(it)); + } +} + +function Regression::Map() +{ + print(""); + print("--Map--"); + print(" GetMapSize(): " + AIMap.GetMapSize()); + print(" GetMapSizeX(): " + AIMap.GetMapSizeX()); + print(" GetMapSizeY(): " + AIMap.GetMapSizeY()); + print(" GetTileX(123): " + AIMap.GetTileX(123)); + print(" GetTileY(123): " + AIMap.GetTileY(123)); + print(" GetTileIndex(): " + AIMap.GetTileIndex(123, 0)); + print(" GetTileIndex(): " + AIMap.GetTileIndex(0, 123)); + print(" GetTileIndex(): " + AIMap.GetTileIndex(0, 0)); + print(" GetTileIndex(): " + AIMap.GetTileIndex(-1, -1)); + print(" GetTileIndex(): " + AIMap.GetTileIndex(10000, 10000)); + print(" IsValidTile(123): " + AIMap.IsValidTile(123)); + print(" GetTileX(124): " + AIMap.GetTileX(124)); + print(" GetTileY(124): " + AIMap.GetTileY(124)); + print(" IsValidTile(124): " + AIMap.IsValidTile(124)); + print(" IsValidTile(0): " + AIMap.IsValidTile(0)); + print(" IsValidTile(-1): " + AIMap.IsValidTile(-1)); + print(" IsValidTile(): " + AIMap.IsValidTile(AIMap.GetMapSize())); + print(" IsValidTile(): " + AIMap.IsValidTile(AIMap.GetMapSize() - AIMap.GetMapSizeX() - 2)); + print(" DemolishTile(): " + AITile.DemolishTile(19592)); + print(" DemolishTile(): " + AITile.DemolishTile(19335)); + print(" Distance"); + print(" DistanceManhattan(): " + AIMap.DistanceManhattan(1, 10000)); + print(" DistanceMax(): " + AIMap.DistanceMax(1, 10000)); + print(" DistanceSquare(): " + AIMap.DistanceSquare(1, 10000)); + print(" DistanceFromEdge(): " + AIMap.DistanceFromEdge(10000)); +} + +function Regression::Marine() +{ + print(""); + print("--AIMarine--"); + + print(" IsWaterDepotTile(): " + AIMarine.IsWaterDepotTile(32116)); + print(" IsDockTile(): " + AIMarine.IsDockTile(32116)); + print(" IsBuoyTile(): " + AIMarine.IsBuoyTile(32116)); + print(" IsLockTile(): " + AIMarine.IsLockTile(32116)); + print(" IsCanalTile(): " + AIMarine.IsCanalTile(32116)); + + print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF)); + print(" BuildWaterDepot(): " + AIMarine.BuildWaterDepot(28479, 28478)); + print(" BuildDock(): " + AIMarine.BuildDock(29253, AIStation.STATION_JOIN_ADJACENT)); + print(" BuildBuoy(): " + AIMarine.BuildBuoy(28481)); + print(" BuildLock(): " + AIMarine.BuildLock(28487)); + print(" HasTransportType(): " + AITile.HasTransportType(32127, AITile.TRANSPORT_WATER)); + print(" BuildCanal(): " + AIMarine.BuildCanal(32127)); + print(" HasTransportType(): " + AITile.HasTransportType(32127, AITile.TRANSPORT_WATER)); + print(" IsWaterDepotTile(): " + AIMarine.IsWaterDepotTile(28479)); + print(" IsDockTile(): " + AIMarine.IsDockTile(29253)); + print(" IsBuoyTile(): " + AIMarine.IsBuoyTile(28481)); + print(" IsLockTile(): " + AIMarine.IsLockTile(28487)); + print(" IsCanalTile(): " + AIMarine.IsCanalTile(32127)); + print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF)); + + local list = AIWaypointList(AIWaypoint.WAYPOINT_BUOY); + print(""); + print("--AIWaypointList(BUOY)--"); + print(" Count(): " + list.Count()); + print(" Location ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + AIWaypoint.GetLocation(i)); + } + print(" HasWaypointType:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + AIWaypoint.HasWaypointType(i, AIWaypoint.WAYPOINT_RAIL) + " " + AIWaypoint.HasWaypointType(i, AIWaypoint.WAYPOINT_BUOY) + " " + AIWaypoint.HasWaypointType(i, AIWaypoint.WAYPOINT_ANY)); + } + print(""); + + print(" RemoveWaterDepot(): " + AIMarine.RemoveWaterDepot(28479)); + print(" RemoveDock(): " + AIMarine.RemoveDock(29253)); + print(" RemoveBuoy(): " + AIMarine.RemoveBuoy(28481)); + print(" RemoveLock(): " + AIMarine.RemoveLock(28487)); + print(" RemoveCanal(): " + AIMarine.RemoveCanal(32127)); + print(" IsWaterDepotTile(): " + AIMarine.IsWaterDepotTile(28479)); + print(" IsDockTile(): " + AIMarine.IsDockTile(29253)); + print(" IsBuoyTile(): " + AIMarine.IsBuoyTile(28481)); + print(" IsLockTile(): " + AIMarine.IsLockTile(28487)); + print(" IsCanalTile(): " + AIMarine.IsCanalTile(32127)); + print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF)); + + print(" BuildWaterDepot(): " + AIMarine.BuildWaterDepot(28479, 28480)); + print(" BuildDock(): " + AIMarine.BuildDock(29253, AIStation.STATION_JOIN_ADJACENT)); +} + +function Regression::Order() +{ + print(""); + print("--Order--"); + print(" GetOrderCount(): " + AIOrder.GetOrderCount(12)); + print(" GetOrderDestination(): " + AIOrder.GetOrderDestination(12, 1)); + print(" AreOrderFlagsValid(): " + AIOrder.AreOrderFlagsValid(33416, AIOrder.OF_TRANSFER)); + print(" AreOrderFlagsValid(): " + AIOrder.AreOrderFlagsValid(33416, AIOrder.OF_TRANSFER | AIOrder.OF_UNLOAD)); + print(" AreOrderFlagsValid(): " + AIOrder.AreOrderFlagsValid(33416, AIOrder.OF_TRANSFER | AIOrder.OF_FULL_LOAD)); + print(" AreOrderFlagsValid(): " + AIOrder.AreOrderFlagsValid(33417, AIOrder.OF_SERVICE_IF_NEEDED)); + print(" AreOrderFlagsValid(): " + AIOrder.AreOrderFlagsValid(33417, AIOrder.OF_STOP_IN_DEPOT)); + print(" AreOrderFlagsValid(): " + AIOrder.AreOrderFlagsValid(0, AIOrder.OF_SERVICE_IF_NEEDED | AIOrder.OF_GOTO_NEAREST_DEPOT)); + print(" IsValidConditionalOrder(): " + AIOrder.IsValidConditionalOrder(AIOrder.OC_LOAD_PERCENTAGE, AIOrder.CF_EQUALS)); + print(" IsValidConditionalOrder(): " + AIOrder.IsValidConditionalOrder(AIOrder.OC_RELIABILITY, AIOrder.CF_IS_TRUE)); + print(" IsValidConditionalOrder(): " + AIOrder.IsValidConditionalOrder(AIOrder.OC_REQUIRES_SERVICE, AIOrder.CF_IS_FALSE)); + print(" IsValidConditionalOrder(): " + AIOrder.IsValidConditionalOrder(AIOrder.OC_AGE, AIOrder.CF_INVALID)); + print(" IsValidVehicleOrder(): " + AIOrder.IsValidVehicleOrder(12, 1)); + print(" IsGotoStationOrder(): " + AIOrder.IsGotoStationOrder(12, 1)); + print(" IsGotoDepotOrder(): " + AIOrder.IsGotoDepotOrder(12, 1)); + print(" IsGotoWaypointOrder(): " + AIOrder.IsGotoWaypointOrder(12, 1)); + print(" IsConditionalOrder(): " + AIOrder.IsConditionalOrder(12, 1)); + print(" IsCurrentOrderPartOfOrderList(): " + AIOrder.IsCurrentOrderPartOfOrderList(12)); + print(" GetOrderFlags(): " + AIOrder.GetOrderFlags(12, 1)); + print(" AppendOrder(): " + AIOrder.AppendOrder(12, 33416, AIOrder.OF_TRANSFER)); + print(" InsertOrder(): " + AIOrder.InsertOrder(12, 0, 33416, AIOrder.OF_TRANSFER)); + print(" GetOrderCount(): " + AIOrder.GetOrderCount(12)); + print(" IsValidVehicleOrder(): " + AIOrder.IsValidVehicleOrder(12, 1)); + print(" IsGotoStationOrder(): " + AIOrder.IsGotoStationOrder(12, 1)); + print(" IsGotoDepotOrder(): " + AIOrder.IsGotoDepotOrder(12, 1)); + print(" IsGotoWaypointOrder(): " + AIOrder.IsGotoWaypointOrder(12, 1)); + print(" IsConditionalOrder(): " + AIOrder.IsConditionalOrder(12, 1)); + print(" IsCurrentOrderPartOfOrderList(): " + AIOrder.IsCurrentOrderPartOfOrderList(12)); + print(" GetOrderFlags(): " + AIOrder.GetOrderFlags(12, 0)); + print(" GetOrderFlags(): " + AIOrder.GetOrderFlags(12, 1)); + print(" GetOrderJumpTo(): " + AIOrder.GetOrderJumpTo(12, 1)); + print(" RemoveOrder(): " + AIOrder.RemoveOrder(12, 0)); + print(" SetOrderFlags(): " + AIOrder.SetOrderFlags(12, 0, AIOrder.OF_FULL_LOAD)); + print(" GetOrderFlags(): " + AIOrder.GetOrderFlags(12, 0)); + print(" GetOrderDestination(): " + AIOrder.GetOrderDestination(12, 0)); + print(" CopyOrders(): " + AIOrder.CopyOrders(12, 1)); + print(" CopyOrders(): " + AIOrder.CopyOrders(13, 12)); + print(" ShareOrders(): " + AIOrder.ShareOrders(13, 1)); + print(" ShareOrders(): " + AIOrder.ShareOrders(13, 12)); + print(" UnshareOrders(): " + AIOrder.UnshareOrders(13)); + print(" AppendOrder(): " + AIOrder.AppendOrder(12, 33421, AIOrder.OF_NONE)); + + print(" GetStopLocation(): " + AIOrder.GetStopLocation(13, 0)); + print(" BuildVehicle(): " + AIVehicle.BuildVehicle(23596, 8)); + print(" BuildRailStation(): " + AIRail.BuildRailStation(7958, AIRail.RAILTRACK_NE_SW, 1, 1, AIStation.STATION_NEW)); + print(" AppendOrder(): " + AIOrder.AppendOrder(20, 7958, AIOrder.OF_NONE)); + print(" GetOrderCount(): " + AIOrder.GetOrderCount(20)); + print(" GetStopLocation(): " + AIOrder.GetStopLocation(20, 0)); + print(" SetStopLocation(): " + AIOrder.SetStopLocation(20, 0, AIOrder.STOPLOCATION_MIDDLE)); + print(" GetStopLocation(): " + AIOrder.GetStopLocation(20, 0)); + + local list = AIVehicleList_Station(3); + + print(""); + print("--VehicleList_Station--"); + print(" Count(): " + list.Count()); + list.Valuate(AIVehicle.GetLocation); + print(" Location ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + print(" foreach():"); + foreach (idx, val in list) { + print(" " + idx + " => " + val); + } +} + +function Regression::RailTypeList() +{ + local list = AIRailTypeList(); + + print(""); + print("--RailTypeList--"); + print(" Count(): " + list.Count()); + print(" ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" RailType: " + i); + print(" GetName(): " + AIRail.GetName(i)); + print(" IsRailTypeAvailable(): " + AIRail.IsRailTypeAvailable(i)); + print(" GetMaxSpeed(): " + AIRail.GetMaxSpeed(i)); + } +} + +function Regression::Rail() +{ + AIRail.SetCurrentRailType(0); + + print(""); + print("--Rail--"); + print(" IsRailTile(): " + AIRail.IsRailTile(10002)); + print(" BuildRailTrack(): " + AIRail.BuildRailTrack(10002, AIRail.RAILTRACK_NW_SE)); + print(" BuildSignal(): " + AIRail.BuildSignal(10002, 10258, AIRail.SIGNALTYPE_PBS)); + print(" RemoveRailTrack(): " + AIRail.RemoveRailTrack(10002, AIRail.RAILTRACK_NW_NE)); + print(" RemoveRailTrack(): " + AIRail.RemoveRailTrack(10002, AIRail.RAILTRACK_NW_SE)); + print(" BuildRail(): " + AIRail.BuildRail(10002, 10003, 10006)); + print(" HasTransportType(): " + AITile.HasTransportType(10005, AITile.TRANSPORT_RAIL)); + print(" HasTransportType(): " + AITile.HasTransportType(10006, AITile.TRANSPORT_RAIL)); + print(" RemoveRail(): " + AIRail.RemoveRail(10005, 10004, 10001)); + + print(" Depot"); + print(" IsRailTile(): " + AIRail.IsRailTile(33411)); + print(" BuildRailDepot(): " + AIRail.BuildRailDepot(0, 1)); + print(" BuildRailDepot(): " + AIRail.BuildRailDepot(33411, 33411)); + print(" BuildRailDepot(): " + AIRail.BuildRailDepot(33411, 33414)); + print(" BuildRailDepot(): " + AIRail.BuildRailDepot(33411, 33412)); + print(" GetRailDepotFrontTile(): " + AIRail.GetRailDepotFrontTile(33411)); + print(" IsBuildable(): " + AITile.IsBuildable(33411)); + local list = AIDepotList(AITile.TRANSPORT_RAIL); + print(" DepotList"); + print(" Count(): " + list.Count()); + list.Valuate(AITile.GetDistanceManhattanToTile, 0); + print(" Depot distance from (0,0) ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + print(" RemoveDepot(): " + AITile.DemolishTile(33411)); + print(" BuildRailDepot(): " + AIRail.BuildRailDepot(23596, 23597)); + + print(" Station"); + print(" BuildRailStation(): " + AIRail.BuildRailStation(0, AIRail.RAILTRACK_NE_SW, 1, 1, AIStation.STATION_NEW)); + print(" BuildRailStation(): " + AIRail.BuildRailStation(7958, AIRail.RAILTRACK_NE_SW, 4, 5, AIStation.STATION_NEW)); + print(" IsRailStationTile(): " + AIRail.IsRailStationTile(7957)); + print(" IsRailStationTile(): " + AIRail.IsRailStationTile(7958)); + print(" IsRailStationTile(): " + AIRail.IsRailStationTile(7959)); + print(" RemoveRailStationTileRectangle():" + AIRail.RemoveRailStationTileRectangle(7959, 7959, false)); + print(" IsRailStationTile(): " + AIRail.IsRailStationTile(7957)); + print(" IsRailStationTile(): " + AIRail.IsRailStationTile(7958)); + print(" IsRailStationTile(): " + AIRail.IsRailStationTile(7959)); + print(" DemolishTile(): " + AITile.DemolishTile(7960)); + print(" IsRailStationTile(): " + AIRail.IsRailStationTile(7957)); + print(" IsRailStationTile(): " + AIRail.IsRailStationTile(7958)); + print(" IsRailStationTile(): " + AIRail.IsRailStationTile(7959)); +} + +function Regression::Road() +{ + print(""); + print("--Road--"); + print(" Road"); + print(" IsRoadTile(): " + AIRoad.IsRoadTile(33411)); + print(" BuildRoad(): " + AIRoad.BuildRoad(0, 1)); + print(" BuildRoad(): " + AIRoad.BuildRoad(33411, 33411)); + print(" HasTransportType(): " + AITile.HasTransportType(33413, AITile.TRANSPORT_ROAD)); + print(" BuildRoad(): " + AIRoad.BuildRoad(33411, 33414)); + print(" HasTransportType(): " + AITile.HasTransportType(33413, AITile.TRANSPORT_ROAD)); + print(" AreRoadTilesConnected(): " + AIRoad.AreRoadTilesConnected(33412, 33413)); + print(" IsRoadTile(): " + AIRoad.IsRoadTile(33411)); + print(" HasRoadType(Road): " + AIRoad.HasRoadType(33411, AIRoad.ROADTYPE_ROAD)); + print(" HasRoadType(Tram): " + AIRoad.HasRoadType(33411, AIRoad.ROADTYPE_TRAM)); + print(" GetNeighbourRoadCount(): " + AIRoad.GetNeighbourRoadCount(33412)); + print(" RemoveRoad(): " + AIRoad.RemoveRoad(33411, 33411)); + print(" RemoveRoad(): " + AIRoad.RemoveRoad(33411, 33412)); + print(" RemoveRoad(): " + AIRoad.RemoveRoad(19590, 19590)); + print(" RemoveRoad(): " + AIRoad.RemoveRoad(33411, 33414)); + print(" BuildOneWayRoad(): " + AIRoad.BuildOneWayRoad(33411, 33414)); + print(" AreRoadTilesConnected(): " + AIRoad.AreRoadTilesConnected(33412, 33413)); + print(" AreRoadTilesConnected(): " + AIRoad.AreRoadTilesConnected(33413, 33412)); + print(" BuildOneWayRoad(): " + AIRoad.BuildOneWayRoad(33413, 33412)); + print(" AreRoadTilesConnected(): " + AIRoad.AreRoadTilesConnected(33412, 33413)); + print(" AreRoadTilesConnected(): " + AIRoad.AreRoadTilesConnected(33413, 33412)); + print(" BuildOneWayRoad(): " + AIRoad.BuildOneWayRoad(33412, 33413)); + print(" BuildOneWayRoad(): " + AIRoad.BuildOneWayRoad(33413, 33412)); + print(" AreRoadTilesConnected(): " + AIRoad.AreRoadTilesConnected(33412, 33413)); + print(" AreRoadTilesConnected(): " + AIRoad.AreRoadTilesConnected(33413, 33412)); + print(" RemoveRoad(): " + AIRoad.RemoveRoad(33411, 33412)); + print(" IsRoadTypeAvailable(Road): " + AIRoad.IsRoadTypeAvailable(AIRoad.ROADTYPE_ROAD)); + print(" IsRoadTypeAvailable(Tram): " + AIRoad.IsRoadTypeAvailable(AIRoad.ROADTYPE_TRAM)); + print(" SetCurrentRoadType(Tram): " + AIRoad.SetCurrentRoadType(AIRoad.ROADTYPE_TRAM)); + print(" GetCurrentRoadType(): " + AIRoad.GetCurrentRoadType()); + + print(" Depot"); + print(" IsRoadTile(): " + AIRoad.IsRoadTile(33411)); + print(" BuildRoadDepot(): " + AIRoad.BuildRoadDepot(0, 1)); + print(" BuildRoadDepot(): " + AIRoad.BuildRoadDepot(33411, 33411)); + print(" BuildRoadDepot(): " + AIRoad.BuildRoadDepot(33411, 33414)); + print(" BuildRoadDepot(): " + AIRoad.BuildRoadDepot(33411, 33412)); + print(" HasRoadType(Road): " + AIRoad.HasRoadType(33411, AIRoad.ROADTYPE_ROAD)); + print(" HasRoadType(Tram): " + AIRoad.HasRoadType(33411, AIRoad.ROADTYPE_TRAM)); + print(" GetLastError(): " + AIError.GetLastError()); + print(" GetLastErrorString(): " + AIError.GetLastErrorString()); + print(" GetErrorCategory(): " + AIError.GetErrorCategory()); + print(" IsRoadTile(): " + AIRoad.IsRoadTile(33411)); + print(" GetRoadDepotFrontTile(): " + AIRoad.GetRoadDepotFrontTile(33411)); + print(" IsRoadDepotTile(): " + AIRoad.IsRoadDepotTile(33411)); + print(" IsBuildable(): " + AITile.IsBuildable(33411)); + local list = AIDepotList(AITile.TRANSPORT_ROAD); + print(" DepotList"); + print(" Count(): " + list.Count()); + list.Valuate(AITile.GetDistanceManhattanToTile, 0); + print(" Depot distance from (0,0) ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + print(" RemoveRoadDepot(): " + AIRoad.RemoveRoadDepot(33411)); + print(" RemoveRoadDepot(): " + AIRoad.RemoveRoadDepot(33411)); + + print(" Station"); + print(" IsRoadTile(): " + AIRoad.IsRoadTile(33411)); + print(" BuildRoadStation(): " + AIRoad.BuildRoadStation(0, 1, AIRoad.ROADVEHTYPE_BUS, AIStation.STATION_JOIN_ADJACENT)); + print(" BuildRoadStation(): " + AIRoad.BuildRoadStation(33411, 33411, AIRoad.ROADVEHTYPE_BUS, AIStation.STATION_JOIN_ADJACENT)); + print(" BuildRoadStation(): " + AIRoad.BuildRoadStation(33411, 33414, AIRoad.ROADVEHTYPE_BUS, AIStation.STATION_JOIN_ADJACENT)); + print(" BuildRoadStation(): " + AIRoad.BuildRoadStation(33411, 33412, AIRoad.ROADVEHTYPE_BUS, AIStation.STATION_JOIN_ADJACENT)); + print(" IsStationTile(): " + AITile.IsStationTile(33411)); + print(" IsStationTile(): " + AITile.IsStationTile(33412)); + print(" HasRoadType(Road): " + AIRoad.HasRoadType(33411, AIRoad.ROADTYPE_ROAD)); + print(" HasRoadType(Tram): " + AIRoad.HasRoadType(33411, AIRoad.ROADTYPE_TRAM)); + print(" IsRoadTile(): " + AIRoad.IsRoadTile(33411)); + print(" GetDriveThroughBackTile(): " + AIRoad.GetDriveThroughBackTile(33411)); + print(" GetRoadStationFrontTile(): " + AIRoad.GetRoadStationFrontTile(33411)); + print(" IsRoadStationTile(): " + AIRoad.IsRoadStationTile(33411)); + print(" IsDriveThroughRoadStationTile: " + AIRoad.IsDriveThroughRoadStationTile(33411)); + print(" RemoveRoadStation(): " + AIRoad.RemoveRoadStation(33411)); + print(" RemoveRoadStation(): " + AIRoad.RemoveRoadStation(33411)); + + print(" Station Types"); + print(" BuildRoadStation(bus): " + AIRoad.BuildRoadStation(33411, 33410, AIRoad.ROADVEHTYPE_BUS, AIStation.STATION_JOIN_ADJACENT)); + print(" BuildRoadStation(truck): " + AIRoad.BuildRoadStation(33421, 33422, AIRoad.ROADVEHTYPE_TRUCK, AIStation.STATION_JOIN_ADJACENT)); + print(" BuildRoadStation(truck): " + AIRoad.BuildRoadStation(33412, 33413, AIRoad.ROADVEHTYPE_TRUCK, AIStation.STATION_JOIN_ADJACENT)); + print(" BuildRoadStation(bus): " + AIRoad.BuildRoadStation(33411 + 256, 33411, AIRoad.ROADVEHTYPE_BUS, AIStation.STATION_JOIN_ADJACENT)); + print(" BuildRoadStation(truck): " + AIRoad.BuildRoadStation(33412 + 256, 33412 + 256 + 256, AIRoad.ROADVEHTYPE_TRUCK, AIStation.STATION_JOIN_ADJACENT)); + print(" BuildDriveThroughRoadStation(bus-drive): " + AIRoad.BuildDriveThroughRoadStation(33413, 33412, AIRoad.ROADVEHTYPE_BUS, AIStation.STATION_JOIN_ADJACENT)); + print(" BuildDriveThroughRoadStation(truck-drive): " + AIRoad.BuildDriveThroughRoadStation(33414, 33413, AIRoad.ROADVEHTYPE_TRUCK, AIStation.STATION_JOIN_ADJACENT)); + print(" BuildDriveThroughRoadStation(bus-drive): " + AIRoad.BuildDriveThroughRoadStation(33415, 33414, AIRoad.ROADVEHTYPE_BUS, AIStation.STATION_JOIN_ADJACENT)); + print(" BuildDriveThroughRoadStation(truck-drive): " + AIRoad.BuildDriveThroughRoadStation(33416, 33415, AIRoad.ROADVEHTYPE_TRUCK, AIStation.STATION_JOIN_ADJACENT)); + print(" BuildRoadDepot(): " + AIRoad.BuildRoadDepot(33417, 33418)); + print(" GetRoadStationFrontTile(): " + AIRoad.GetRoadStationFrontTile(33411 + 256)); + print(" GetRoadStationFrontTile(): " + AIRoad.GetRoadStationFrontTile(33412 + 256)); + print(" IsDriveThroughRoadStationTile: " + AIRoad.IsDriveThroughRoadStationTile(33415)); + print(" IsBuildable(): " + AITile.IsBuildable(33415)); + print(" GetDriveThroughBackTile(): " + AIRoad.GetDriveThroughBackTile(33415)); + print(" GetRoadStationFrontTile(): " + AIRoad.GetRoadStationFrontTile(33415)); + print(" IsRoadTile(): " + AIRoad.IsRoadTile(33415)); +} + +function Regression::Sign() +{ + local j = 0; + + print(""); + print("--Sign--"); + print(" BuildSign(33410, 'Some Sign'): " + AISign.BuildSign(33410, "Some Sign")); + print(" BuildSign(33411, 'Test'): " + AISign.BuildSign(33411, "Test")); + print(" SetName(1, 'Test2'): " + AISign.SetName(1, "Test2")); + local sign_id = AISign.BuildSign(33409, "Some other Sign"); + print(" BuildSign(33409, 'Some other Sign'): " + sign_id); + print(" RemoveSign(" + sign_id + "): " + AISign.RemoveSign(sign_id)); + print(""); + local list = AISignList(); + list.Sort(AIList.SORT_BY_ITEM, AIList.SORT_ASCENDING); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + j++; + print(" Sign " + i); + print(" IsValidSign(): " + AISign.IsValidSign(i)); + print(" GetName(): " + AISign.GetName(i)); + print(" GetLocation(): " + AISign.GetLocation(i)); + } + print(" Valid Signs: " + j); +} + +function Regression::Station() +{ + print(""); + print("--Station--"); + print(" IsValidStation(0): " + AIStation.IsValidStation(0)); + print(" IsValidStation(1000): " + AIStation.IsValidStation(1000)); + print(" GetName(0): " + AIStation.GetName(0)); + print(" SetName(0): " + AIStation.SetName(0, "Look, a station")); + print(" GetName(0): " + AIStation.GetName(0)); + print(" GetLocation(1): " + AIStation.GetLocation(1)); + print(" GetLocation(1000): " + AIStation.GetLocation(1000)); + print(" GetStationID(33411): " + AIStation.GetStationID(33411)); + print(" GetStationID(34411): " + AIStation.GetStationID(34411)); + print(" GetStationID(33411): " + AIStation.GetStationID(33411)); + print(" HasRoadType(3, TRAM): " + AIStation.HasRoadType(3, AIRoad.ROADTYPE_TRAM)); + print(" HasRoadType(3, ROAD): " + AIStation.HasRoadType(3, AIRoad.ROADTYPE_ROAD)); + print(" HasRoadType(33411, TRAM): " + AIRoad.HasRoadType(33411, AIRoad.ROADTYPE_TRAM)); + print(" HasRoadType(33411, ROAD): " + AIRoad.HasRoadType(33411, AIRoad.ROADTYPE_ROAD)); + print(" HasStationType(3, BUS): " + AIStation.HasStationType(3, AIStation.STATION_BUS_STOP)); + print(" HasStationType(3, TRAIN): " + AIStation.HasStationType(3, AIStation.STATION_TRAIN)); + + print(" GetCoverageRadius(BUS): " + AIStation.GetCoverageRadius(AIStation.STATION_BUS_STOP)); + print(" GetCoverageRadius(TRUCK): " + AIStation.GetCoverageRadius(AIStation.STATION_TRUCK_STOP)); + print(" GetCoverageRadius(TRAIN): " + AIStation.GetCoverageRadius(AIStation.STATION_TRAIN)); + + print(" GetNearestTown(): " + AIStation.GetNearestTown(0)); + print(" GetNearestTown(): " + AIStation.GetNearestTown(10000)); + print(" GetNearestTown(): " + AIStation.GetNearestTown(3)); + + print(""); + print("--CargoWaiting--"); + for (local cargo = 0; cargo <= 1000; cargo += 1000) { + for (local station0 = 0; station0 <= 1000; station0 += 1000) { + print(" GetCargoWaiting(" + station0 + ", " + cargo + "): " + + AIStation.GetCargoWaiting(station0, cargo)); + for (local station1 = 0; station1 <= 1000; station1 += 1000) { + print(" GetCargoWaitingFrom(" + station0 + ", " + station1 + ", " + cargo + "): " + + AIStation.GetCargoWaitingFrom(station0, station1, cargo)); + print(" GetCargoWaitingVia(" + station0 + ", " + station1 + ", " + cargo + "): " + + AIStation.GetCargoWaitingFrom(station0, station1, cargo)); + for (local station2 = 0; station2 <= 1000; station2 += 1000) { + print(" GetCargoWaitingFromVia(" + station0 + ", " + station1 + ", " + station2 + ", " + cargo + "): " + + AIStation.GetCargoWaitingFromVia(station0, station1, station2, cargo)); + } + } + } + } + + print(""); + print("--CargoPlanned--"); + for (local cargo = 0; cargo <= 1000; cargo += 1000) { + for (local station0 = 0; station0 <= 1000; station0 += 1000) { + print(" GetCargoPlanned(" + station0 + ", " + cargo + "): " + + AIStation.GetCargoPlanned(station0, cargo)); + for (local station1 = 0; station1 <= 1000; station1 += 1000) { + print(" GetCargoPlannedFrom(" + station0 + ", " + station1 + ", " + cargo + "): " + + AIStation.GetCargoPlannedFrom(station0, station1, cargo)); + print(" GetCargoPlannedVia(" + station0 + ", " + station1 + ", " + cargo + "): " + + AIStation.GetCargoPlannedFrom(station0, station1, cargo)); + for (local station2 = 0; station2 <= 1000; station2 += 1000) { + print(" GetCargoPlannedFromVia(" + station0 + ", " + station1 + ", " + station2 + ", " + cargo + "): " + + AIStation.GetCargoPlannedFromVia(station0, station1, station2, cargo)); + } + } + } + } +} + +function Regression::Tile() +{ + print(""); + print("--Tile--"); + print(" HasTreeOnTile(): " + AITile.HasTreeOnTile(33148)); + print(" IsFarmTile(): " + AITile.IsFarmTile(32892)); + print(" IsRockTile(): " + AITile.IsRockTile(31606)); + print(" IsRoughTile(): " + AITile.IsRoughTile(33674)); + print(" HasTreeOnTile(): " + AITile.HasTreeOnTile(33404)); + print(" IsFarmTile(): " + AITile.IsFarmTile(33404)); + print(" IsRockTile(): " + AITile.IsRockTile(33404)); + print(" IsRoughTile(): " + AITile.IsRoughTile(33404)); + print(" IsSnowTile(): " + AITile.IsSnowTile(33404)); + print(" IsDesertTile(): " + AITile.IsDesertTile(33404)); + print(" PlantTree(): " + AITile.PlantTree(33404)); + print(" HasTreeOnTile(): " + AITile.HasTreeOnTile(33404)); + print(" PlantTree(): " + AITile.PlantTree(33404)); + print(" HasTreeOnTile(): " + AITile.HasTreeOnTile(33661)); + print(" PlantTreeRectangle(): " + AITile.PlantTreeRectangle(33404, 2, 2)); + print(" HasTreeOnTile(): " + AITile.HasTreeOnTile(33661)); +} + +function Regression::TileList() +{ + local list = AITileList(); + + print(""); + print("--TileList--"); + print(" Count(): " + list.Count()); + list.AddRectangle(27631 - 256 * 1, 256 * 1 + 27631 + 2); + print(" Count(): " + list.Count()); + + list.Valuate(AITile.GetSlope); + print(" Slope(): done"); + print(" Count(): " + list.Count()); + print(" ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + print(" " + i + " => " + AITile.GetComplementSlope(list.GetValue(i))); + print(" " + i + " => " + AITile.IsSteepSlope(list.GetValue(i))); + print(" " + i + " => " + AITile.IsHalftileSlope(list.GetValue(i))); + } + list.Clear(); + + print(""); + print("--TileList--"); + print(" Count(): " + list.Count()); + list.AddRectangle(34436, 256 * 2 + 34436 + 8); + print(" Count(): " + list.Count()); + + list.Valuate(AITile.GetCornerHeight, AITile.CORNER_N); + print(" Height(): done"); + print(" Count(): " + list.Count()); + print(" ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + + list.Valuate(AITile.GetCornerHeight, AITile.CORNER_N); + print(" CornerHeight(North): done"); + print(" Count(): " + list.Count()); + print(" ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + + list.Valuate(AITile.GetMinHeight); + print(" MinHeight(): done"); + print(" Count(): " + list.Count()); + print(" ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + + list.Valuate(AITile.GetMaxHeight); + print(" MaxHeight(): done"); + print(" Count(): " + list.Count()); + print(" ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + + list.Valuate(AITile.GetSlope); + list.KeepValue(0); + print(" Slope(): done"); + print(" KeepValue(0): done"); + print(" Count(): " + list.Count()); + print(" ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + + list.Clear(); + list.AddRectangle(41895 - 256 * 2, 256 * 2 + 41895 + 8); + list.Valuate(AITile.IsBuildable); + list.KeepValue(1); + print(" Buildable(): done"); + print(" KeepValue(1): done"); + print(" Count(): " + list.Count()); + + list.Valuate(AITile.IsBuildableRectangle, 3, 3); + print(" BuildableRectangle(3, 3) ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AITile.GetDistanceManhattanToTile, 30000); + print(" DistanceManhattanToTile(30000) ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AITile.GetDistanceSquareToTile, 30000); + print(" DistanceSquareToTile(30000) ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + + list.AddRectangle(31895 - 256 * 5, 256 * 5 + 31895 + 8); + + list.Valuate(AITile.GetOwner); + print(" GetOwner() ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AITile.GetTownAuthority); + print(" GetTownAuthority() ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AITile.GetClosestTown); + print(" GetClosestTown() ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + + list.Valuate(AITile.GetCargoAcceptance, 0, 1, 1, 3); + list.KeepAboveValue(10); + print(" CargoAcceptance(): done"); + print(" KeepAboveValue(10): done"); + print(" Count(): " + list.Count()); + print(" ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + + list.Valuate(AIRoad.IsRoadTile); + list.KeepValue(1); + print(" RoadTile(): done"); + print(" KeepValue(1): done"); + print(" Count(): " + list.Count()); + print(" ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + + list.Valuate(AIRoad.GetNeighbourRoadCount); + list.KeepValue(1); + print(" NeighbourRoadCount():done"); + print(" KeepValue(1): done"); + print(" Count(): " + list.Count()); + print(" ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + + list.AddRectangle(54421 - 256 * 2, 256 * 2 + 54421 + 8); + list.Valuate(AITile.IsWaterTile); + print(" Water(): done"); + print(" Count(): " + list.Count()); + print(" ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + + list = AITileList_IndustryAccepting(0, 3); + print(""); + print("--TileList_IndustryAccepting--"); + print(" Count(): " + list.Count()); + list.Valuate(AITile.GetCargoAcceptance, 3, 1, 1, 3); + print(" Location ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + + list = AITileList_IndustryProducing(1, 3); + print(""); + print("--TileList_IndustryProducing--"); + print(" Count(): " + list.Count()); + list.Valuate(AITile.GetCargoProduction, 7, 1, 1, 3); + print(" Location ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + + list = AITileList_StationType(4, AIStation.STATION_BUS_STOP); + print(""); + print("--TileList_StationType--"); + print(" Count(): " + list.Count()); + print(" Location ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } +} + +function Regression::Town() +{ + local j = 0; + + print(""); + print("--Town--"); + print(" GetTownCount(): " + AITown.GetTownCount()); + local list = AITownList(); + list.Sort(AIList.SORT_BY_ITEM, AIList.SORT_ASCENDING); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + if (AITown.IsValidTown(i)) j++; + print(" Town " + i); + print(" IsValidTown(): " + AITown.IsValidTown(i)); + print(" GetName(): " + AITown.GetName(i)); + print(" GetPopulation(): " + AITown.GetPopulation(i)); + print(" GetLocation(): " + AITown.GetLocation(i)); + print(" GetHouseCount(): " + AITown.GetHouseCount(i)); + print(" GetRating(): " + AITown.GetRating(i, AICompany.COMPANY_SELF)); + print(" IsCity(): " + AITown.IsCity(i)); + } + print(" Valid Towns: " + j); + print(" GetTownCount(): " + AITown.GetTownCount()); +} + +function Regression::TownList() +{ + local list = AITownList(); + + print(""); + print("--TownList--"); + print(" Count(): " + list.Count()); + list.Valuate(AITown.GetLocation); + print(" Location ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AITown.GetDistanceManhattanToTile, 30000); + print(" DistanceManhattanToTile(30000) ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AITown.GetDistanceSquareToTile, 30000); + print(" DistanceSquareToTile(30000) ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AITown.IsWithinTownInfluence, AITown.GetLocation(0)); + print(" IsWithinTownInfluence(" + AITown.GetLocation(0) + ") ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AITown.GetAllowedNoise); + print(" GetAllowedNoise() ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AITown.GetPopulation); + list.KeepAboveValue(500); + print(" KeepAboveValue(500): done"); + print(" Count(): " + list.Count()); + print(" Population ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + + print(" HasStatue(): " + AITown.HasStatue(list.Begin())); + print(" GetRoadReworkDuration(): " + AITown.GetRoadReworkDuration(list.Begin())); + print(" GetExclusiveRightsCompany(): " + AITown.GetExclusiveRightsCompany(list.Begin())); + print(" GetExclusiveRightsDuration(): " + AITown.GetExclusiveRightsDuration(list.Begin())); + print(" IsActionAvailable(BUILD_STATUE): " + AITown.IsActionAvailable(list.Begin(), AITown.TOWN_ACTION_BUILD_STATUE)); + print(" PerformTownAction(BUILD_STATUE): " + AITown.PerformTownAction(list.Begin(), AITown.TOWN_ACTION_BUILD_STATUE)); + print(" IsActionAvailable(BUILD_STATUE): " + AITown.IsActionAvailable(list.Begin(), AITown.TOWN_ACTION_BUILD_STATUE)); + print(" HasStatue(): " + AITown.HasStatue(list.Begin())); +} + +function Regression::Tunnel() +{ + print(""); + print("--Tunnel--"); + print(" IsTunnelTile(): " + AITunnel.IsTunnelTile(29050)); + print(" RemoveTunnel(): " + AITunnel.RemoveTunnel(29050)); + print(" GetOtherTunnelEnd(): " + AITunnel.GetOtherTunnelEnd(29050)); + print(" BuildTunnel(): " + AITunnel.BuildTunnel(AIVehicle.VT_ROAD, 29050)); + print(" GetOtherTunnelEnd(): " + AITunnel.GetOtherTunnelEnd(29050)); + print(" IsTunnelTile(): " + AITunnel.IsTunnelTile(29050)); + print(" IsTunnelTile(): " + AITunnel.IsTunnelTile(28026)); + print(" RemoveTunnel(): " + AITunnel.RemoveTunnel(29050)); + print(" IsTunnelTile(): " + AITunnel.IsTunnelTile(29050)); + + print(" --Errors--"); + print(" BuildTunnel(): " + AITunnel.BuildTunnel(AIVehicle.VT_ROAD, 7529)); + print(" BuildTunnel(): " + AITunnel.BuildTunnel(AIVehicle.VT_ROAD, 8043)); + print(" GetLastErrorString(): " + AIError.GetLastErrorString()); + print(" RemoveTunnel(): " + AITunnel.RemoveTunnel(7529)); +} + +function Regression::Vehicle() +{ + local accounting = AIAccounting(); + + print(""); + print("--Vehicle--"); + print(" IsValidVehicle(-1): " + AIVehicle.IsValidVehicle(-1)); + print(" IsValidVehicle(0): " + AIVehicle.IsValidVehicle(0)); + print(" IsValidVehicle(12): " + AIVehicle.IsValidVehicle(12)); + print(" ISValidVehicle(9999): " + AIVehicle.IsValidVehicle(9999)); + + local bank = AICompany.GetBankBalance(AICompany.COMPANY_SELF); + + print(" BuildVehicle(): " + AIVehicle.BuildVehicle(33417, 153)); + print(" IsValidVehicle(12): " + AIVehicle.IsValidVehicle(12)); + print(" CloneVehicle(): " + AIVehicle.CloneVehicle(33417, 12, true)); + + local bank_after = AICompany.GetBankBalance(AICompany.COMPANY_SELF); + + print(" --Accounting--"); + print(" GetCosts(): " + accounting.GetCosts()); + print(" Should be: " + (bank - bank_after)); + print(" ResetCosts(): " + accounting.ResetCosts()); + + bank = AICompany.GetBankBalance(AICompany.COMPANY_SELF); + + print(" SellVehicle(13): " + AIVehicle.SellVehicle(13)); + print(" IsInDepot(): " + AIVehicle.IsInDepot(12)); + print(" IsStoppedInDepot(): " + AIVehicle.IsStoppedInDepot(12)); + print(" StartStopVehicle(): " + AIVehicle.StartStopVehicle(12)); + print(" IsInDepot(): " + AIVehicle.IsInDepot(12)); + print(" IsStoppedInDepot(): " + AIVehicle.IsStoppedInDepot(12)); + print(" SendVehicleToDepot(): " + AIVehicle.SendVehicleToDepot(12)); + print(" IsInDepot(): " + AIVehicle.IsInDepot(12)); + print(" IsStoppedInDepot(): " + AIVehicle.IsStoppedInDepot(12)); + + bank_after = AICompany.GetBankBalance(AICompany.COMPANY_SELF); + + print(" --Accounting--"); + print(" GetCosts(): " + accounting.GetCosts()); + print(" Should be: " + (bank - bank_after)); + + print(" GetName(): " + AIVehicle.GetName(12)); + print(" SetName(): " + AIVehicle.SetName(12, "MyVehicleName")); + print(" GetName(): " + AIVehicle.GetName(12)); + print(" CloneVehicle(): " + AIVehicle.CloneVehicle(33417, 12, true)); + + print(" --VehicleData--"); + print(" GetLocation(): " + AIVehicle.GetLocation(12)); + print(" GetEngineType(): " + AIVehicle.GetEngineType(12)); + print(" GetUnitNumber(): " + AIVehicle.GetUnitNumber(12)); + print(" GetAge(): " + AIVehicle.GetAge(12)); + print(" GetMaxAge(): " + AIVehicle.GetMaxAge(12)); + print(" GetAgeLeft(): " + AIVehicle.GetAgeLeft(12)); + print(" GetCurrentSpeed(): " + AIVehicle.GetCurrentSpeed(12)); + print(" GetRunningCost(): " + AIVehicle.GetRunningCost(12)); + print(" GetProfitThisYear(): " + AIVehicle.GetProfitThisYear(12)); + print(" GetProfitLastYear(): " + AIVehicle.GetProfitLastYear(12)); + print(" GetCurrentValue(): " + AIVehicle.GetCurrentValue(12)); + print(" GetVehicleType(): " + AIVehicle.GetVehicleType(12)); + print(" GetRoadType(): " + AIVehicle.GetRoadType(12)); + print(" GetCapacity(): " + AIVehicle.GetCapacity(12, 10)); + print(" GetCargoLoad(): " + AIVehicle.GetCargoLoad(12, 10)); + print(" IsInDepot(): " + AIVehicle.IsInDepot(12)); + print(" GetNumWagons(): " + AIVehicle.GetNumWagons(12)); + print(" GetWagonEngineType(): " + AIVehicle.GetWagonEngineType(12, 0)); + print(" GetWagonAge(): " + AIVehicle.GetWagonAge(12, 0)); + print(" GetLength(): " + AIVehicle.GetLength(12)); + + print(" GetOwner(): " + AITile.GetOwner(32119)); + print(" BuildVehicle(): " + AIVehicle.BuildVehicle(32119, 219)); + print(" IsValidVehicle(14): " + AIVehicle.IsValidVehicle(14)); + print(" IsInDepot(14): " + AIVehicle.IsInDepot(14)); + print(" IsStoppedInDepot(14): " + AIVehicle.IsStoppedInDepot(14)); + print(" IsValidVehicle(15): " + AIVehicle.IsValidVehicle(15)); + print(" IsInDepot(15): " + AIVehicle.IsInDepot(15)); + print(" IsStoppedInDepot(15): " + AIVehicle.IsStoppedInDepot(15)); + + print(" BuildVehicle(): " + AIVehicle.BuildVehicle(28479, 204)); + print(" IsValidVehicle(16): " + AIVehicle.IsValidVehicle(16)); + print(" IsInDepot(16): " + AIVehicle.IsInDepot(16)); + print(" IsStoppedInDepot(16): " + AIVehicle.IsStoppedInDepot(16)); + + print(" BuildRailDepot(): " + AIRail.BuildRailDepot(10008, 10000)); + print(" BuildVehicle(): " + AIVehicle.BuildVehicle(10008, 9)); + print(" BuildVehicle(): " + AIVehicle.BuildVehicle(10008, 27)); + print(" BuildVehicle(): " + AIVehicle.BuildVehicle(10008, 27)); + print(" MoveWagonChain(): " + AIVehicle.MoveWagonChain(18, 0, 17, 0)); + print(" GetNumWagons(): " + AIVehicle.GetNumWagons(17)); + print(" GetLength(): " + AIVehicle.GetLength(17)); + print(" GetWagonEngineType(): " + AIVehicle.GetWagonEngineType(17, 0)); + print(" GetWagonAge(): " + AIVehicle.GetWagonAge(17, 0)); + print(" GetWagonEngineType(): " + AIVehicle.GetWagonEngineType(17, 1)); + print(" GetWagonAge(): " + AIVehicle.GetWagonAge(17, 1)); + print(" GetWagonEngineType(): " + AIVehicle.GetWagonEngineType(17 2)); + print(" GetWagonAge(): " + AIVehicle.GetWagonAge(17, 2)); + print(" GetWagonEngineType(): " + AIVehicle.GetWagonEngineType(17 3)); + print(" GetWagonAge(): " + AIVehicle.GetWagonAge(17, 3)); + + print(" --Errors--"); + print(" RefitVehicle(): " + AIVehicle.RefitVehicle(12, 0)); + print(" GetLastErrorString(): " + AIError.GetLastErrorString()); + print(" SellVehicle(): " + AIVehicle.SellVehicle(12)); + print(" GetLastErrorString(): " + AIError.GetLastErrorString()); + print(" SendVehicleToDepot(): " + AIVehicle.SendVehicleToDepot(13)); + print(" GetLastErrorString(): " + AIError.GetLastErrorString()); + + local list = AIVehicleList(); + + print(""); + print("--VehicleList--"); + print(" Count(): " + list.Count()); + list.Valuate(AIVehicle.GetLocation); + print(" Location ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIVehicle.GetEngineType); + print(" EngineType ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIVehicle.GetUnitNumber); + print(" UnitNumber ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIVehicle.GetAge); + print(" Age ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIVehicle.GetMaxAge); + print(" MaxAge ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIVehicle.GetAgeLeft); + print(" AgeLeft ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIVehicle.GetCurrentSpeed); + print(" CurrentSpeed ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIVehicle.GetRunningCost); + print(" RunningCost ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIVehicle.GetProfitThisYear); + print(" ProfitThisYear ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIVehicle.GetProfitLastYear); + print(" ProfitLastYear ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIVehicle.GetCurrentValue); + print(" CurrentValue ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIVehicle.GetVehicleType); + print(" VehicleType ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIVehicle.GetRoadType); + print(" RoadType ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIVehicle.GetCapacity, 10); + print(" VehicleType ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIVehicle.GetCargoLoad, 10); + print(" VehicleType ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } +} + +function Regression::PrintSubsidy(subsidy_id) +{ + print(" --Subsidy (" + subsidy_id + ") --"); + print(" IsValidSubsidy(): " + AISubsidy.IsValidSubsidy(subsidy_id)); + print(" IsAwarded(): " + AISubsidy.IsAwarded(subsidy_id)); + print(" GetAwardedTo(): " + AISubsidy.GetAwardedTo(subsidy_id)); + print(" GetExpireDate(): " + AISubsidy.GetExpireDate(subsidy_id)); + print(" GetSourceType(): " + AISubsidy.GetSourceType(subsidy_id)); + print(" GetSourceIndex(): " + AISubsidy.GetSourceIndex(subsidy_id)); + print(" GetDestinationType(): " + AISubsidy.GetDestinationType(subsidy_id)); + print(" GetDestinationIndex(): " + AISubsidy.GetDestinationIndex(subsidy_id)); + print(" GetCargoType(): " + AISubsidy.GetCargoType(subsidy_id)); +} + +function Regression::Math() +{ + print(""); + print("--Math--"); + print(" -2147483648 < -2147483647: " + (-2147483648 < -2147483647)); + print(" -2147483648 < -1 : " + (-2147483648 < -1 )); + print(" -2147483648 < 0 : " + (-2147483648 < 0 )); + print(" -2147483648 < 1 : " + (-2147483648 < 1 )); + print(" -2147483648 < 2147483647: " + (-2147483648 < 2147483647)); + + print(" -2147483647 < -2147483648: " + (-2147483647 < -2147483648)); + print(" -1 < -2147483648: " + (-1 < -2147483648)); + print(" 0 < -2147483648: " + ( 0 < -2147483648)); + print(" 1 < -2147483648: " + ( 1 < -2147483648)); + print(" 2147483647 < -2147483648: " + ( 2147483647 < -2147483648)); + + print(" -1 > 2147483647: " + (-1 > 2147483647)); + print(" -1 > 1 : " + (-1 > 1 )); + print(" -1 > 0 : " + (-1 > 0 )); + print(" -1 > -1 : " + (-1 > -1 )); + print(" -1 > -2147483648: " + (-1 > -2147483648)); + + print(" 1 > 2147483647: " + ( 1 > 2147483647)); + print(" 1 > 1 : " + ( 1 > 1 )); + print(" 1 > 0 : " + ( 1 > 0 )); + print(" 1 > -1 : " + ( 1 > -1 )); + print(" 1 > -2147483648: " + ( 1 > -2147483648)); + + print(" 2147483647 > 2147483646: " + ( 2147483647 > 2147483646)); + print(" 2147483647 > 1 : " + ( 2147483647 > 1 )); + print(" 2147483647 > 0 : " + ( 2147483647 > 0 )); + print(" 2147483647 > -1 : " + ( 2147483647 > -1 )); + print(" 2147483647 > -2147483648: " + ( 2147483647 > -2147483648)); + + print(" 2147483646 > 2147483647: " + ( 2147483646 > 2147483647)); + print(" 1 > 2147483647: " + ( 1 > 2147483647)); + print(" 0 > 2147483647: " + ( 0 > 2147483647)); + print(" -1 > 2147483647: " + (-1 > 2147483647)); + print(" -2147483648 > 2147483647: " + (-2147483648 > 2147483647)); + + print(" 13725 > -2147483648: " + ( 13725 > -2147483648)); +} + +function Regression::Start() +{ + this.TestInit(); + this.Std(); + this.Base(); + this.List(); + + /* Do this first as it gains maximum loan (which is faked to quite a lot). */ + this.Company(); + + this.Airport(); + this.Bridge(); + this.BridgeList(); + this.Cargo(); + this.CargoList(); + this.Engine(); + this.EngineList(); + this.Group(); + this.Industry(); + this.IndustryList(); + this.IndustryTypeList(); + this.Map(); + this.Marine(); + this.Prices(); + this.Rail(); + this.RailTypeList(); + this.Road(); + this.Sign(); + this.Station(); + this.Tile(); + this.TileList(); + this.Town(); + this.TownList(); + this.Tunnel(); + this.Vehicle(); + /* Order has to be after Vehicle */ + this.Order(); + print(""); + print(" First Subsidy Test"); + PrintSubsidy(0); + + while (AIEventController.IsEventWaiting()) { + local e = AIEventController.GetNextEvent(); + print(" GetNextEvent: " + (e == null ? "null" : "instance")); + print(" GetEventType: " + e.GetEventType()); + switch (e.GetEventType()) { + case AIEvent.ET_SUBSIDY_OFFER: { + local c = AIEventSubsidyOffer.Convert(e); + print(" EventName: SubsidyOffer"); + PrintSubsidy(c.GetSubsidyID()); + } break; + + case AIEvent.ET_VEHICLE_WAITING_IN_DEPOT: { + local c = AIEventVehicleWaitingInDepot.Convert(e); + print(" EventName: VehicleWaitingInDepot"); + print(" VehicleID: " + c.GetVehicleID()); + } break; + + default: + print(" Unknown Event"); + break; + } + } + print(" IsEventWaiting: false"); + + this.Math(); +} + diff --git a/bin/ai/regression/tst_regression/require.nut b/bin/ai/regression/tst_regression/require.nut new file mode 100644 index 0000000..360e1c2 --- /dev/null +++ b/bin/ai/regression/tst_regression/require.nut @@ -0,0 +1,4 @@ +/* $Id$ */ + +print(" Required this file"); + diff --git a/bin/ai/regression/tst_regression/result.txt b/bin/ai/regression/tst_regression/result.txt new file mode 100644 index 0000000..c909e79 --- /dev/null +++ b/bin/ai/regression/tst_regression/result.txt @@ -0,0 +1,9222 @@ + +--TestInit-- + Ops: 9988 + TickTest: 1 + TickTest: 2 + Ops: 9990 + SetCommandDelay: (null : 0x00000000) + IsValid(vehicle.plane_speed): true + vehicle.plane_speed: 2 + Required this file + min(6, 3): 3 + min(3, 6): 3 + max(6, 3): 6 + max(3, 6): 6 + AIList Consistency Tests + + Value Descending + 40 + 25 + 10 + + 40 + 30 + 20 + 10 + 40 + 30 + 20 + 10 + + 40 + 30 + 20 + 10 + + Value Ascending + 5 + 20 + 35 + + 10 + 20 + 30 + 40 + 10 + 20 + 30 + 40 + + 10 + 20 + 30 + 40 + + Item Descending + 40 + 25 + 10 + + 40 + 30 + 20 + 10 + + 40 + 30 + 20 + 10 + + Item Ascending + 5 + 20 + 35 + + 10 + 20 + 30 + 40 + + 10 + 20 + 30 + 40 + Ops: 8673 + +--Std-- + abs(-21): 21 + abs( 21): 21 + +--AIBase-- + Rand(): -54346916 + Rand(): -937374575 + Rand(): 823953997 + RandRange(0): 0 + RandRange(0): 0 + RandRange(0): 0 + RandRange(1): 0 + RandRange(1): 0 + RandRange(1): 0 + RandRange(2): 1 + RandRange(2): 1 + RandRange(2): 1 + RandRange(1000000): 966676 + RandRange(1000000): 289525 + RandRange(1000000): 170283 + Chance(1, 2): false + Chance(1, 2): true + Chance(1, 2): false + +--List-- + IsEmpty(): true + Count(): 101 + HasItem(1050): false + HasItem(1051): true + IsEmpty(): false + List Dump: + 1 => 1 + 2 => 2 + 1000 => 1000 + 1001 => 1001 + 1002 => 1002 + 1003 => 1003 + 1004 => 1004 + 1005 => 1005 + 1006 => 1006 + 1007 => 1007 + 1008 => 1008 + 1009 => 1009 + 1010 => 1010 + 1011 => 1011 + 1012 => 1012 + 1013 => 1013 + 1014 => 1014 + 1015 => 1015 + 1016 => 1016 + 1017 => 1017 + 1018 => 1018 + 1019 => 1019 + 1020 => 1020 + 1021 => 1021 + 1022 => 1022 + 1023 => 1023 + 1024 => 1024 + 1025 => 1025 + 1026 => 1026 + 1027 => 1027 + 1028 => 1028 + 1029 => 1029 + 1030 => 1030 + 1031 => 1031 + 1032 => 1032 + 1033 => 1033 + 1034 => 1034 + 1035 => 1035 + 1036 => 1036 + 1037 => 1037 + 1038 => 1038 + 1039 => 1039 + 1040 => 1040 + 1041 => 1041 + 1042 => 1042 + 1043 => 1043 + 1044 => 1044 + 1045 => 1045 + 1046 => 1046 + 1047 => 1047 + 1048 => 1048 + 1049 => 1049 + 1051 => 12 + 1052 => 1052 + 1053 => 1053 + 1054 => 1054 + 1055 => 1055 + 1056 => 1056 + 1057 => 1057 + 1058 => 1058 + 1059 => 1059 + 1060 => 1060 + 1061 => 1061 + 1062 => 1062 + 1063 => 1063 + 1064 => 1064 + 1065 => 1065 + 1066 => 1066 + 1067 => 1067 + 1068 => 1068 + 1069 => 1069 + 1070 => 1070 + 1071 => 1071 + 1072 => 1072 + 1073 => 1073 + 1074 => 1074 + 1075 => 1075 + 1076 => 1076 + 1077 => 1077 + 1078 => 1078 + 1079 => 1079 + 1080 => 1080 + 1081 => 1081 + 1082 => 1082 + 1083 => 1083 + 1084 => 1084 + 1085 => 1085 + 1086 => 1086 + 1087 => 1087 + 1088 => 1088 + 1089 => 1089 + 1090 => 1090 + 1091 => 1091 + 1092 => 1092 + 1093 => 1093 + 1094 => 1094 + 1095 => 1095 + 1096 => 1096 + 1097 => 1097 + 1098 => 1098 + 1099 => 1099 + Custom ListDump: + 1 => 4343 + 2 => 8686 + 1000 => 4343000 + 1001 => 4347343 + 1002 => 4351686 + 1003 => 4356029 + 1004 => 4360372 + 1005 => 4364715 + 1006 => 4369058 + 1007 => 4373401 + 1008 => 4377744 + 1009 => 4382087 + 1010 => 4386430 + 1011 => 4390773 + 1012 => 4395116 + 1013 => 4399459 + 1014 => 4403802 + 1015 => 4408145 + 1016 => 4412488 + 1017 => 4416831 + 1018 => 4421174 + 1019 => 4425517 + 1020 => 4429860 + 1021 => 4434203 + 1022 => 4438546 + 1023 => 4442889 + 1024 => 4447232 + 1025 => 4451575 + 1026 => 4455918 + 1027 => 4460261 + 1028 => 4464604 + 1029 => 4468947 + 1030 => 4473290 + 1031 => 4477633 + 1032 => 4481976 + 1033 => 4486319 + 1034 => 4490662 + 1035 => 4495005 + 1036 => 4499348 + 1037 => 4503691 + 1038 => 4508034 + 1039 => 4512377 + 1040 => 4516720 + 1041 => 4521063 + 1042 => 4525406 + 1043 => 4529749 + 1044 => 4534092 + 1045 => 4538435 + 1046 => 4542778 + 1047 => 4547121 + 1048 => 4551464 + 1049 => 4555807 + 1051 => 4564493 + 1052 => 4568836 + 1053 => 4573179 + 1054 => 4577522 + 1055 => 4581865 + 1056 => 4586208 + 1057 => 4590551 + 1058 => 4594894 + 1059 => 4599237 + 1060 => 4603580 + 1061 => 4607923 + 1062 => 4612266 + 1063 => 4616609 + 1064 => 4620952 + 1065 => 4625295 + 1066 => 4629638 + 1067 => 4633981 + 1068 => 4638324 + 1069 => 4642667 + 1070 => 4647010 + 1071 => 4651353 + 1072 => 4655696 + 1073 => 4660039 + 1074 => 4664382 + 1075 => 4668725 + 1076 => 4673068 + 1077 => 4677411 + 1078 => 4681754 + 1079 => 4686097 + 1080 => 4690440 + 1081 => 4694783 + 1082 => 4699126 + 1083 => 4703469 + 1084 => 4707812 + 1085 => 4712155 + 1086 => 4716498 + 1087 => 4720841 + 1088 => 4725184 + 1089 => 4729527 + 1090 => 4733870 + 1091 => 4738213 + 1092 => 4742556 + 1093 => 4746899 + 1094 => 4751242 + 1095 => 4755585 + 1096 => 4759928 + 1097 => 4764271 + 1098 => 4768614 + 1099 => 4772957 + Custom ListDump: + 1 => 42 + 2 => 84 + 1000 => 42000 + 1001 => 42042 + 1002 => 42084 + 1003 => 42126 + 1004 => 42168 + 1005 => 42210 + 1006 => 42252 + 1007 => 42294 + 1008 => 42336 + 1009 => 42378 + 1010 => 42420 + 1011 => 42462 + 1012 => 42504 + 1013 => 42546 + 1014 => 42588 + 1015 => 42630 + 1016 => 42672 + 1017 => 42714 + 1018 => 42756 + 1019 => 42798 + 1020 => 42840 + 1021 => 42882 + 1022 => 42924 + 1023 => 42966 + 1024 => 43008 + 1025 => 43050 + 1026 => 43092 + 1027 => 43134 + 1028 => 43176 + 1029 => 43218 + 1030 => 43260 + 1031 => 43302 + 1032 => 43344 + 1033 => 43386 + 1034 => 43428 + 1035 => 43470 + 1036 => 43512 + 1037 => 43554 + 1038 => 43596 + 1039 => 43638 + 1040 => 43680 + 1041 => 43722 + 1042 => 43764 + 1043 => 43806 + 1044 => 43848 + 1045 => 43890 + 1046 => 43932 + 1047 => 43974 + 1048 => 44016 + 1049 => 44058 + 1051 => 44142 + 1052 => 44184 + 1053 => 44226 + 1054 => 44268 + 1055 => 44310 + 1056 => 44352 + 1057 => 44394 + 1058 => 44436 + 1059 => 44478 + 1060 => 44520 + 1061 => 44562 + 1062 => 44604 + 1063 => 44646 + 1064 => 44688 + 1065 => 44730 + 1066 => 44772 + 1067 => 44814 + 1068 => 44856 + 1069 => 44898 + 1070 => 44940 + 1071 => 44982 + 1072 => 45024 + 1073 => 45066 + 1074 => 45108 + 1075 => 45150 + 1076 => 45192 + 1077 => 45234 + 1078 => 45276 + 1079 => 45318 + 1080 => 45360 + 1081 => 45402 + 1082 => 45444 + 1083 => 45486 + 1084 => 45528 + 1085 => 45570 + 1086 => 45612 + 1087 => 45654 + 1088 => 45696 + 1089 => 45738 + 1090 => 45780 + 1091 => 45822 + 1092 => 45864 + 1093 => 45906 + 1094 => 45948 + 1095 => 45990 + 1096 => 46032 + 1097 => 46074 + 1098 => 46116 + 1099 => 46158 + Randomize ListDump: + 1 => -200078348 + 2 => -29799264 + 1000 => 1630721656 + 1001 => 959306175 + 1002 => 1527421791 + 1003 => 1259692483 + 1004 => -1289244298 + 1005 => -1572996668 + 1006 => -2069479746 + 1007 => -1819131606 + 1008 => -1007163964 + 1009 => -1185394870 + 1010 => -1471365065 + 1011 => 364354366 + 1012 => -1478084253 + 1013 => 405281367 + 1014 => -11170062 + 1015 => 156767750 + 1016 => 1288924796 + 1017 => 1796884876 + 1018 => -1947073702 + 1019 => -1999614238 + 1020 => -231292809 + 1021 => 966621566 + 1022 => -606766557 + 1023 => -1138727825 + 1024 => -749544262 + 1025 => 2004771271 + 1026 => 686734186 + 1027 => 923274744 + 1028 => -1672035149 + 1029 => -1642064950 + 1030 => 1363389551 + 1031 => -559500928 + 1032 => 1656196991 + 1033 => 1655354425 + 1034 => -1027156689 + 1035 => 1952644328 + 1036 => 1217870217 + 1037 => 242274100 + 1038 => 201816080 + 1039 => 2127464758 + 1040 => 446043650 + 1041 => -319728455 + 1042 => 204701002 + 1043 => -571265398 + 1044 => -1422217131 + 1045 => -391208397 + 1046 => -1822628371 + 1047 => -1499755350 + 1048 => -1422137641 + 1049 => 1621693134 + 1051 => -1428728134 + 1052 => -147587573 + 1053 => 681719500 + 1054 => 1172011190 + 1055 => -1834344882 + 1056 => 1157634586 + 1057 => 1902133676 + 1058 => -1967780161 + 1059 => -1618025531 + 1060 => -810220453 + 1061 => 1582854921 + 1062 => -410004643 + 1063 => 1159917159 + 1064 => -1377804984 + 1065 => -738843914 + 1066 => -1578756103 + 1067 => -464090986 + 1068 => 1711504679 + 1069 => 545330655 + 1070 => 379462570 + 1071 => 514511099 + 1072 => -1813251176 + 1073 => 1424958266 + 1074 => -825255131 + 1075 => 539054595 + 1076 => -1764192010 + 1077 => -1243277769 + 1078 => 2017874281 + 1079 => -1972353607 + 1080 => 1879761467 + 1081 => 1638986560 + 1082 => -1832287507 + 1083 => -492411882 + 1084 => 658940812 + 1085 => -1044199400 + 1086 => 1586504918 + 1087 => -125492611 + 1088 => -1562883174 + 1089 => -1013778441 + 1090 => 1560228607 + 1091 => -550265689 + 1092 => 524767105 + 1093 => -713387661 + 1094 => 1425927738 + 1095 => 942653932 + 1096 => 1233220698 + 1097 => 1313602368 + 1098 => -140318584 + 1099 => 1199179892 + KeepTop(10): + 1 => -200078348 + 2 => -29799264 + 1000 => 1630721656 + 1001 => 959306175 + 1002 => 1527421791 + 1003 => 1259692483 + 1004 => -1289244298 + 1005 => -1572996668 + 1006 => -2069479746 + 1007 => -1819131606 + KeepBottom(8): + 1000 => 1630721656 + 1001 => 959306175 + 1002 => 1527421791 + 1003 => 1259692483 + 1004 => -1289244298 + 1005 => -1572996668 + 1006 => -2069479746 + 1007 => -1819131606 + RemoveBottom(2): + 1000 => 1630721656 + 1001 => 959306175 + 1002 => 1527421791 + 1003 => 1259692483 + 1004 => -1289244298 + 1005 => -1572996668 + RemoveTop(2): + 1002 => 1527421791 + 1003 => 1259692483 + 1004 => -1289244298 + 1005 => -1572996668 + RemoveList({1003, 1004}): + 1002 => 1527421791 + 1005 => -1572996668 + KeepList({1003, 1004, 1005}): + 1005 => -1572996668 + AddList({1005, 4000, 4001, 4002}): + 1005 => 1005 + 4000 => 8000 + 4001 => 8002 + 4002 => 8004 + foreach(): + 1005 => 1005 + 4000 => 50 + 4001 => 8002 + 4002 => 8004 + 4006 => 12 + []: + 4000 => 50 + IsEmpty(): true + 0 => 5 (true) +ERROR: Next() is invalid as Begin() is never called +ERROR: IsEnd() is invalid as Begin() is never called + 0 => 5 (false) + 0 => 5 (true) + 2 => 6 (true) + 3 => 6 (true) + 9 => 0 (false) + +--Company-- + SetName(): true + SetName(): true + SetName(): true + SetName(): false + GetLastErrorString(): ERR_NAME_IS_NOT_UNIQUE + GetName(): Regression + GetPresidentName(): E. McAlpine + SetPresidentName(): true + GetPresidentName(): Regression AI + GetBankBalance(): 100000 + GetName(): (null : 0x00000000) + GetLoanAmount(): 100000 + GetMaxLoanAmount(): 500000 + GetLoanInterval(): 10000 + SetLoanAmount(1): false + SetLoanAmount(100): false + SetLoanAmount(10000): true + GetLastErrorString(): ERR_NONE + GetBankBalance(): 10000 + GetLoanAmount(): 10000 + SetMinimumLoanAmount(31337): true + GetBankBalance(): 40000 + GetLoanAmount(): 40000 + SetLoanAmount(10000): true + GetBankBalance(): 500000 + GetLoanAmount(): 500000 + GetCompanyHQ(): -1 + BuildCompanyHQ(): true + GetCompanyHQ(): 33151 + BuildCompanyHQ(): true + GetCompanyHQ(): 33153 + BuildCompanyHQ(): false + GetLastErrorString(): ERR_AREA_NOT_CLEAR + GetAutoRenewStatus(); false + SetAutoRenewStatus(true); true + GetAutoRenewStatus(); true + SetAutoRenewStatus(true); true + SetAutoRenewStatus(false); true + GetAutoRenewMonths(); 6 + SetAutoRenewMonths(-12); true + GetAutoRenewMonths(); -12 + SetAutoRenewMonths(-12); true + SetAutoRenewMonths(6); true + GetAutoRenewMoney(); 100000 + SetAutoRenewMoney(200000); true + GetAutoRenewMoney(); 200000 + SetAutoRenewMoney(200000); true + SetAutoRenewMoney(100000); true + Quarter: -1 + GetQuarterlyIncome(); -1 + GetQuarterlyExpenses(); -1 + GetQuarterlyCargoDelivered(); -1 + GetQuarterlyPerformanceRating(); -1 + GetQuarterlyCompanyValue(); -1 + Quarter: 0 + GetQuarterlyIncome(); 0 + GetQuarterlyExpenses(); -210 + GetQuarterlyCargoDelivered(); 0 + GetQuarterlyPerformanceRating(); -1 + GetQuarterlyCompanyValue(); 1 + Quarter: 1 + GetQuarterlyIncome(); 0 + GetQuarterlyExpenses(); 0 + GetQuarterlyCargoDelivered(); 0 + GetQuarterlyPerformanceRating(); 0 + GetQuarterlyCompanyValue(); 0 + Quarter: 2 + GetQuarterlyIncome(); 0 + GetQuarterlyExpenses(); 0 + GetQuarterlyCargoDelivered(); 0 + GetQuarterlyPerformanceRating(); 0 + GetQuarterlyCompanyValue(); 0 + Quarter: 3 + GetQuarterlyIncome(); 0 + GetQuarterlyExpenses(); 0 + GetQuarterlyCargoDelivered(); 0 + GetQuarterlyPerformanceRating(); 0 + GetQuarterlyCompanyValue(); 0 + Quarter: 4 + GetQuarterlyIncome(); 0 + GetQuarterlyExpenses(); 0 + GetQuarterlyCargoDelivered(); 0 + GetQuarterlyPerformanceRating(); 0 + GetQuarterlyCompanyValue(); 0 + Quarter: 5 + GetQuarterlyIncome(); 0 + GetQuarterlyExpenses(); 0 + GetQuarterlyCargoDelivered(); 0 + GetQuarterlyPerformanceRating(); 0 + GetQuarterlyCompanyValue(); 0 + Quarter: 6 + GetQuarterlyIncome(); 0 + GetQuarterlyExpenses(); 0 + GetQuarterlyCargoDelivered(); 0 + GetQuarterlyPerformanceRating(); 0 + GetQuarterlyCompanyValue(); 0 + Quarter: 7 + GetQuarterlyIncome(); 0 + GetQuarterlyExpenses(); 0 + GetQuarterlyCargoDelivered(); 0 + GetQuarterlyPerformanceRating(); 0 + GetQuarterlyCompanyValue(); 0 + Quarter: 8 + GetQuarterlyIncome(); 0 + GetQuarterlyExpenses(); 0 + GetQuarterlyCargoDelivered(); 0 + GetQuarterlyPerformanceRating(); 0 + GetQuarterlyCompanyValue(); 0 + Quarter: 9 + GetQuarterlyIncome(); 0 + GetQuarterlyExpenses(); 0 + GetQuarterlyCargoDelivered(); 0 + GetQuarterlyPerformanceRating(); 0 + GetQuarterlyCompanyValue(); 0 + Quarter: 10 + GetQuarterlyIncome(); 0 + GetQuarterlyExpenses(); 0 + GetQuarterlyCargoDelivered(); 0 + GetQuarterlyPerformanceRating(); 0 + GetQuarterlyCompanyValue(); 0 + Quarter: 11 + GetQuarterlyIncome(); 0 + GetQuarterlyExpenses(); 0 + GetQuarterlyCargoDelivered(); 0 + GetQuarterlyPerformanceRating(); 0 + GetQuarterlyCompanyValue(); 0 + Quarter: 12 + GetQuarterlyIncome(); 0 + GetQuarterlyExpenses(); 0 + GetQuarterlyCargoDelivered(); 0 + GetQuarterlyPerformanceRating(); 0 + GetQuarterlyCompanyValue(); 0 + Quarter: 13 + GetQuarterlyIncome(); 0 + GetQuarterlyExpenses(); 0 + GetQuarterlyCargoDelivered(); 0 + GetQuarterlyPerformanceRating(); 0 + GetQuarterlyCompanyValue(); 0 + Quarter: 14 + GetQuarterlyIncome(); 0 + GetQuarterlyExpenses(); 0 + GetQuarterlyCargoDelivered(); 0 + GetQuarterlyPerformanceRating(); 0 + GetQuarterlyCompanyValue(); 0 + Quarter: 15 + GetQuarterlyIncome(); 0 + GetQuarterlyExpenses(); 0 + GetQuarterlyCargoDelivered(); 0 + GetQuarterlyPerformanceRating(); 0 + GetQuarterlyCompanyValue(); 0 + Quarter: 16 + GetQuarterlyIncome(); 0 + GetQuarterlyExpenses(); 0 + GetQuarterlyCargoDelivered(); 0 + GetQuarterlyPerformanceRating(); 0 + GetQuarterlyCompanyValue(); 0 + Quarter: 17 + GetQuarterlyIncome(); 0 + GetQuarterlyExpenses(); 0 + GetQuarterlyCargoDelivered(); 0 + GetQuarterlyPerformanceRating(); 0 + GetQuarterlyCompanyValue(); 0 + Quarter: 18 + GetQuarterlyIncome(); 0 + GetQuarterlyExpenses(); 0 + GetQuarterlyCargoDelivered(); 0 + GetQuarterlyPerformanceRating(); 0 + GetQuarterlyCompanyValue(); 0 + Quarter: 19 + GetQuarterlyIncome(); 0 + GetQuarterlyExpenses(); 0 + GetQuarterlyCargoDelivered(); 0 + GetQuarterlyPerformanceRating(); 0 + GetQuarterlyCompanyValue(); 0 + Quarter: 20 + GetQuarterlyIncome(); 0 + GetQuarterlyExpenses(); 0 + GetQuarterlyCargoDelivered(); 0 + GetQuarterlyPerformanceRating(); 0 + GetQuarterlyCompanyValue(); 0 + Quarter: 21 + GetQuarterlyIncome(); 0 + GetQuarterlyExpenses(); 0 + GetQuarterlyCargoDelivered(); 0 + GetQuarterlyPerformanceRating(); 0 + GetQuarterlyCompanyValue(); 0 + Quarter: 22 + GetQuarterlyIncome(); 0 + GetQuarterlyExpenses(); 0 + GetQuarterlyCargoDelivered(); 0 + GetQuarterlyPerformanceRating(); 0 + GetQuarterlyCompanyValue(); 0 + Quarter: 23 + GetQuarterlyIncome(); 0 + GetQuarterlyExpenses(); 0 + GetQuarterlyCargoDelivered(); 0 + GetQuarterlyPerformanceRating(); 0 + GetQuarterlyCompanyValue(); 0 + Quarter: 24 + GetQuarterlyIncome(); 0 + GetQuarterlyExpenses(); 0 + GetQuarterlyCargoDelivered(); 0 + GetQuarterlyPerformanceRating(); 0 + GetQuarterlyCompanyValue(); 0 + +--AIAirport-- + IsHangarTile(): false + IsAirportTile(): false + GetHangarOfAirport(): -1 + GetAirportType(): 254 + IsAirportInformationAvailable(-1): false + IsValidAirportType(-1): false + GetAirportWidth(-1): -1 + GetAirportHeight(-1): -1 + GetAirportCoverageRadius(-1): -1 + IsAirportInformationAvailable(0): true + IsValidAirportType(0): true + GetAirportWidth(0): 4 + GetAirportHeight(0): 3 + GetAirportCoverageRadius(0): 4 + IsAirportInformationAvailable(1): true + IsValidAirportType(1): false + GetAirportWidth(1): 6 + GetAirportHeight(1): 6 + GetAirportCoverageRadius(1): 5 + IsAirportInformationAvailable(2): true + IsValidAirportType(2): false + GetAirportWidth(2): 1 + GetAirportHeight(2): 1 + GetAirportCoverageRadius(2): 4 + IsAirportInformationAvailable(3): true + IsValidAirportType(3): false + GetAirportWidth(3): 6 + GetAirportHeight(3): 6 + GetAirportCoverageRadius(3): 6 + IsAirportInformationAvailable(4): true + IsValidAirportType(4): false + GetAirportWidth(4): 7 + GetAirportHeight(4): 7 + GetAirportCoverageRadius(4): 8 + IsAirportInformationAvailable(5): true + IsValidAirportType(5): false + GetAirportWidth(5): 5 + GetAirportHeight(5): 4 + GetAirportCoverageRadius(5): 4 + IsAirportInformationAvailable(6): true + IsValidAirportType(6): false + GetAirportWidth(6): 2 + GetAirportHeight(6): 2 + GetAirportCoverageRadius(6): 4 + IsAirportInformationAvailable(7): true + IsValidAirportType(7): false + GetAirportWidth(7): 9 + GetAirportHeight(7): 11 + GetAirportCoverageRadius(7): 10 + IsAirportInformationAvailable(8): true + IsValidAirportType(8): false + GetAirportWidth(8): 4 + GetAirportHeight(8): 2 + GetAirportCoverageRadius(8): 4 + IsAirportInformationAvailable(9): false + IsValidAirportType(9): false + GetAirportWidth(9): -1 + GetAirportHeight(9): -1 + GetAirportCoverageRadius(9): -1 + GetBankBalance(): 499790 + GetPrice(): 5400 + BuildAirport(): true + IsHangarTile(): false + IsAirportTile(): true + GetAirportType(): 0 + GetHangarOfAirport(): 32119 + IsHangarTile(): true + IsAirportTile(): true + GetAirportType(): 0 + GetBankBalance(): 489890 + RemoveAirport(): true + IsHangarTile(): false + IsAirportTile(): false + GetBankBalance(): 489626 + BuildAirport(): true + +--Bridge-- + Bridge -1 + IsValidBridge(): false + GetName(): (null : 0x00000000) + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxLength(): -1 + GetMinLength(): -1 + Bridge 0 + IsValidBridge(): true + GetName(): Wooden rail bridge + GetMaxSpeed(): 32 + GetPrice(): 450 + GetMaxLength(): 66 + GetMinLength(): 2 + Bridge 1 + IsValidBridge(): true + GetName(): Concrete rail bridge + GetMaxSpeed(): 48 + GetPrice(): 630 + GetMaxLength(): 4 + GetMinLength(): 2 + Bridge 2 + IsValidBridge(): true + GetName(): Steel girder rail bridge + GetMaxSpeed(): 64 + GetPrice(): 811 + GetMaxLength(): 7 + GetMinLength(): 2 + Bridge 3 + IsValidBridge(): true + GetName(): Reinforced concrete suspension rail bridge + GetMaxSpeed(): 80 + GetPrice(): 946 + GetMaxLength(): 12 + GetMinLength(): 4 + Bridge 4 + IsValidBridge(): true + GetName(): Steel suspension rail bridge + GetMaxSpeed(): 96 + GetPrice(): 1042 + GetMaxLength(): 66 + GetMinLength(): 5 + Bridge 5 + IsValidBridge(): true + GetName(): Steel suspension rail bridge + GetMaxSpeed(): 112 + GetPrice(): 1081 + GetMaxLength(): 66 + GetMinLength(): 5 + Bridge 6 + IsValidBridge(): true + GetName(): Steel cantilever rail bridge + GetMaxSpeed(): 160 + GetPrice(): 1261 + GetMaxLength(): 9 + GetMinLength(): 5 + Bridge 7 + IsValidBridge(): true + GetName(): Steel cantilever rail bridge + GetMaxSpeed(): 208 + GetPrice(): 1306 + GetMaxLength(): 10 + GetMinLength(): 5 + Bridge 8 + IsValidBridge(): true + GetName(): Steel cantilever rail bridge + GetMaxSpeed(): 240 + GetPrice(): 1396 + GetMaxLength(): 11 + GetMinLength(): 5 + Bridge 9 + IsValidBridge(): true + GetName(): Steel girder rail bridge + GetMaxSpeed(): 256 + GetPrice(): 1351 + GetMaxLength(): 4 + GetMinLength(): 2 + Bridge 10 + IsValidBridge(): false + GetName(): (null : 0x00000000) + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxLength(): -1 + GetMinLength(): -1 + Bridge 11 + IsValidBridge(): false + GetName(): (null : 0x00000000) + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxLength(): -1 + GetMinLength(): -1 + Bridge 12 + IsValidBridge(): false + GetName(): (null : 0x00000000) + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxLength(): -1 + GetMinLength(): -1 + Bridge 13 + IsValidBridge(): false + GetName(): (null : 0x00000000) + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxLength(): -1 + GetMinLength(): -1 + Valid Bridges: 10 + IsBridgeTile(): false + GetBridgeID(): -1 + RemoveBridge(): false + GetLastErrorString(): ERR_PRECONDITION_FAILED + GetOtherBridgeEnd(): -1 + BuildBridge(): true + IsBridgeTile(): true + GetBridgeID(): 5 + IsBridgeTile(): true + GetBridgeID(): 5 + GetOtherBridgeEnd(): 33155 + BuildBridge(): false + GetLastErrorString(): ERR_ALREADY_BUILT + RemoveBridge(): true + IsBridgeTile(): false + +--BridgeList-- + Count(): 10 + MaxSpeed ListDump: + 9 => 256 + 8 => 240 + 7 => 208 + 6 => 160 + 5 => 112 + 4 => 96 + 3 => 80 + 2 => 64 + 1 => 48 + 0 => 32 + Price ListDump: + 8 => 1396 + 9 => 1351 + 7 => 1306 + 6 => 1261 + 5 => 1081 + 4 => 1042 + 3 => 946 + 2 => 811 + 1 => 630 + 0 => 450 + MaxLength ListDump: + 5 => 66 + 4 => 66 + 0 => 66 + 3 => 12 + 8 => 11 + 7 => 10 + 6 => 9 + 2 => 7 + 9 => 4 + 1 => 4 + MinLength ListDump: + 8 => 5 + 7 => 5 + 6 => 5 + 5 => 5 + 4 => 5 + 3 => 4 + 9 => 2 + 2 => 2 + 1 => 2 + 0 => 2 + +--BridgeList_Length-- + Count(): 3 + MaxSpeed ListDump: + 5 => 112 + 4 => 96 + 0 => 32 + Price ListDump: + 5 => 6489 + 4 => 6252 + 0 => 2703 + +--AICargo-- + Cargo -1 + IsValidCargo(): false + GetCargoLabel(): '(null : 0x00000000)' + IsFreight(): false + HasCargoClass(): false + GetTownEffect(): 0 + GetCargoIncome(0, 0): -1 + GetCargoIncome(10, 10): -1 + GetCargoIncome(100, 10): -1 + GetCargoIncome(10, 100): -1 + GetRoadVehicleTypeForCargo(): 1 + Cargo 0 + IsValidCargo(): true + GetCargoLabel(): 'PASS' + IsFreight(): false + HasCargoClass(): true + GetTownEffect(): 1 + GetCargoIncome(0, 0): 0 + GetCargoIncome(10, 10): 3 + GetCargoIncome(100, 10): 38 + GetCargoIncome(10, 100): 3 + GetRoadVehicleTypeForCargo(): 0 + Cargo 1 + IsValidCargo(): true + GetCargoLabel(): 'COAL' + IsFreight(): true + HasCargoClass(): false + GetTownEffect(): 0 + GetCargoIncome(0, 0): 0 + GetCargoIncome(10, 10): 7 + GetCargoIncome(100, 10): 71 + GetCargoIncome(10, 100): 6 + GetRoadVehicleTypeForCargo(): 1 + Cargo 2 + IsValidCargo(): true + GetCargoLabel(): 'MAIL' + IsFreight(): false + HasCargoClass(): false + GetTownEffect(): 2 + GetCargoIncome(0, 0): 0 + GetCargoIncome(10, 10): 5 + GetCargoIncome(100, 10): 55 + GetCargoIncome(10, 100): 5 + GetRoadVehicleTypeForCargo(): 1 + Cargo 3 + IsValidCargo(): true + GetCargoLabel(): 'OIL_' + IsFreight(): true + HasCargoClass(): false + GetTownEffect(): 0 + GetCargoIncome(0, 0): 0 + GetCargoIncome(10, 10): 5 + GetCargoIncome(100, 10): 53 + GetCargoIncome(10, 100): 5 + GetRoadVehicleTypeForCargo(): 1 + Cargo 4 + IsValidCargo(): true + GetCargoLabel(): 'LVST' + IsFreight(): true + HasCargoClass(): false + GetTownEffect(): 0 + GetCargoIncome(0, 0): 0 + GetCargoIncome(10, 10): 5 + GetCargoIncome(100, 10): 52 + GetCargoIncome(10, 100): 4 + GetRoadVehicleTypeForCargo(): 1 + Cargo 5 + IsValidCargo(): true + GetCargoLabel(): 'GOOD' + IsFreight(): true + HasCargoClass(): false + GetTownEffect(): 3 + GetCargoIncome(0, 0): 0 + GetCargoIncome(10, 10): 7 + GetCargoIncome(100, 10): 74 + GetCargoIncome(10, 100): 6 + GetRoadVehicleTypeForCargo(): 1 + Cargo 6 + IsValidCargo(): true + GetCargoLabel(): 'GRAI' + IsFreight(): true + HasCargoClass(): false + GetTownEffect(): 0 + GetCargoIncome(0, 0): 0 + GetCargoIncome(10, 10): 5 + GetCargoIncome(100, 10): 58 + GetCargoIncome(10, 100): 4 + GetRoadVehicleTypeForCargo(): 1 + Cargo 7 + IsValidCargo(): true + GetCargoLabel(): 'WOOD' + IsFreight(): true + HasCargoClass(): false + GetTownEffect(): 0 + GetCargoIncome(0, 0): 0 + GetCargoIncome(10, 10): 6 + GetCargoIncome(100, 10): 60 + GetCargoIncome(10, 100): 5 + GetRoadVehicleTypeForCargo(): 1 + Cargo 8 + IsValidCargo(): true + GetCargoLabel(): 'IORE' + IsFreight(): true + HasCargoClass(): false + GetTownEffect(): 0 + GetCargoIncome(0, 0): 0 + GetCargoIncome(10, 10): 6 + GetCargoIncome(100, 10): 62 + GetCargoIncome(10, 100): 5 + GetRoadVehicleTypeForCargo(): 1 + Cargo 9 + IsValidCargo(): true + GetCargoLabel(): 'STEL' + IsFreight(): true + HasCargoClass(): false + GetTownEffect(): 0 + GetCargoIncome(0, 0): 0 + GetCargoIncome(10, 10): 6 + GetCargoIncome(100, 10): 69 + GetCargoIncome(10, 100): 6 + GetRoadVehicleTypeForCargo(): 1 + Cargo 10 + IsValidCargo(): true + GetCargoLabel(): 'VALU' + IsFreight(): true + HasCargoClass(): false + GetTownEffect(): 0 + GetCargoIncome(0, 0): 0 + GetCargoIncome(10, 10): 9 + GetCargoIncome(100, 10): 90 + GetCargoIncome(10, 100): 7 + GetRoadVehicleTypeForCargo(): 1 + Cargo 11 + IsValidCargo(): false + GetCargoLabel(): '(null : 0x00000000)' + IsFreight(): false + HasCargoClass(): false + GetTownEffect(): 0 + GetCargoIncome(0, 0): -1 + GetCargoIncome(10, 10): -1 + GetCargoIncome(100, 10): -1 + GetCargoIncome(10, 100): -1 + GetRoadVehicleTypeForCargo(): 1 + Cargo 12 + IsValidCargo(): false + GetCargoLabel(): '(null : 0x00000000)' + IsFreight(): false + HasCargoClass(): false + GetTownEffect(): 0 + GetCargoIncome(0, 0): -1 + GetCargoIncome(10, 10): -1 + GetCargoIncome(100, 10): -1 + GetCargoIncome(10, 100): -1 + GetRoadVehicleTypeForCargo(): 1 + Cargo 13 + IsValidCargo(): false + GetCargoLabel(): '(null : 0x00000000)' + IsFreight(): false + HasCargoClass(): false + GetTownEffect(): 0 + GetCargoIncome(0, 0): -1 + GetCargoIncome(10, 10): -1 + GetCargoIncome(100, 10): -1 + GetCargoIncome(10, 100): -1 + GetRoadVehicleTypeForCargo(): 1 + Cargo 14 + IsValidCargo(): false + GetCargoLabel(): '(null : 0x00000000)' + IsFreight(): false + HasCargoClass(): false + GetTownEffect(): 0 + GetCargoIncome(0, 0): -1 + GetCargoIncome(10, 10): -1 + GetCargoIncome(100, 10): -1 + GetCargoIncome(10, 100): -1 + GetRoadVehicleTypeForCargo(): 1 + +--CargoList-- + Count(): 11 + IsFreight ListDump: + 10 => 1 + 9 => 1 + 8 => 1 + 7 => 1 + 6 => 1 + 5 => 1 + 4 => 1 + 3 => 1 + 1 => 1 + 2 => 0 + 0 => 0 + CargoIncomes(100, 100) ListDump: + 10 => 74 + 5 => 62 + 1 => 62 + 9 => 60 + 8 => 54 + 7 => 54 + 3 => 50 + 2 => 50 + 6 => 49 + 4 => 41 + 0 => 30 + +--CargoList_IndustryAccepting-- + Count(): 1 + ListDump: + 7 + +--CargoList_IndustryProducing-- + Count(): 1 + ListDump: + 7 + +--Engine-- + Engine -1 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 0 + IsValidEngine(): true + GetName(): Kirby Paul Tank (Steam) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): 75 + GetMaxSpeed(): 64 + GetPrice(): 8203 + GetMaxAge(): 5490 + GetRunningCost(): 820 + GetPower(): 300 + GetWeight(): 47 + GetMaxTractiveEffort(): 139 + GetVehicleType(): 0 + GetRailType(): 0 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 1 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 2 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 3 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 4 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 5 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 6 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 7 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 8 + IsValidEngine(): true + GetName(): Chaney 'Jubilee' (Steam) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): 80 + GetMaxSpeed(): 112 + GetPrice(): 15234 + GetMaxAge(): 7686 + GetRunningCost(): 1968 + GetPower(): 1000 + GetWeight(): 131 + GetMaxTractiveEffort(): 388 + GetVehicleType(): 0 + GetRailType(): 0 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 9 + IsValidEngine(): true + GetName(): Ginzu 'A4' (Steam) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): 84 + GetMaxSpeed(): 128 + GetPrice(): 22265 + GetMaxAge(): 7320 + GetRunningCost(): 2296 + GetPower(): 1200 + GetWeight(): 162 + GetMaxTractiveEffort(): 480 + GetVehicleType(): 0 + GetRailType(): 0 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 10 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 11 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 12 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 13 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 14 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 15 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 16 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 17 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 18 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 19 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 20 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 21 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 22 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 23 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 24 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 25 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 26 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 27 + IsValidEngine(): true + GetName(): Passenger Carriage + GetCargoType(): 0 + CanRefitCargo(): false + GetCapacity(): 40 + GetReliability(): -1 + GetMaxSpeed(): 0 + GetPrice(): 1447 + GetMaxAge(): -1 + GetRunningCost(): 0 + GetPower(): -1 + GetWeight(): 25 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 0 + GetRailType(): 0 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 28 + IsValidEngine(): true + GetName(): Mail Van + GetCargoType(): 2 + CanRefitCargo(): false + GetCapacity(): 30 + GetReliability(): -1 + GetMaxSpeed(): 0 + GetPrice(): 1335 + GetMaxAge(): -1 + GetRunningCost(): 0 + GetPower(): -1 + GetWeight(): 21 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 0 + GetRailType(): 0 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 29 + IsValidEngine(): true + GetName(): Coal Truck + GetCargoType(): 1 + CanRefitCargo(): true + GetCapacity(): 30 + GetReliability(): -1 + GetMaxSpeed(): 0 + GetPrice(): 1031 + GetMaxAge(): -1 + GetRunningCost(): 0 + GetPower(): -1 + GetWeight(): 18 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 0 + GetRailType(): 0 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 30 + IsValidEngine(): true + GetName(): Oil Tanker + GetCargoType(): 3 + CanRefitCargo(): false + GetCapacity(): 30 + GetReliability(): -1 + GetMaxSpeed(): 0 + GetPrice(): 1171 + GetMaxAge(): -1 + GetRunningCost(): 0 + GetPower(): -1 + GetWeight(): 24 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 0 + GetRailType(): 0 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 31 + IsValidEngine(): true + GetName(): Livestock Van + GetCargoType(): 4 + CanRefitCargo(): false + GetCapacity(): 25 + GetReliability(): -1 + GetMaxSpeed(): 0 + GetPrice(): 1125 + GetMaxAge(): -1 + GetRunningCost(): 0 + GetPower(): -1 + GetWeight(): 20 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 0 + GetRailType(): 0 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 32 + IsValidEngine(): true + GetName(): Goods Van + GetCargoType(): 5 + CanRefitCargo(): false + GetCapacity(): 25 + GetReliability(): -1 + GetMaxSpeed(): 0 + GetPrice(): 1113 + GetMaxAge(): -1 + GetRunningCost(): 0 + GetPower(): -1 + GetWeight(): 21 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 0 + GetRailType(): 0 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 33 + IsValidEngine(): true + GetName(): Grain Hopper + GetCargoType(): 6 + CanRefitCargo(): false + GetCapacity(): 30 + GetReliability(): -1 + GetMaxSpeed(): 0 + GetPrice(): 1066 + GetMaxAge(): -1 + GetRunningCost(): 0 + GetPower(): -1 + GetWeight(): 19 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 0 + GetRailType(): 0 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 34 + IsValidEngine(): true + GetName(): Wood Truck + GetCargoType(): 7 + CanRefitCargo(): false + GetCapacity(): 30 + GetReliability(): -1 + GetMaxSpeed(): 0 + GetPrice(): 1060 + GetMaxAge(): -1 + GetRunningCost(): 0 + GetPower(): -1 + GetWeight(): 16 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 0 + GetRailType(): 0 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 35 + IsValidEngine(): true + GetName(): Iron Ore Hopper + GetCargoType(): 8 + CanRefitCargo(): false + GetCapacity(): 30 + GetReliability(): -1 + GetMaxSpeed(): 0 + GetPrice(): 1048 + GetMaxAge(): -1 + GetRunningCost(): 0 + GetPower(): -1 + GetWeight(): 19 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 0 + GetRailType(): 0 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 36 + IsValidEngine(): true + GetName(): Steel Truck + GetCargoType(): 9 + CanRefitCargo(): false + GetCapacity(): 20 + GetReliability(): -1 + GetMaxSpeed(): 0 + GetPrice(): 1148 + GetMaxAge(): -1 + GetRunningCost(): 0 + GetPower(): -1 + GetWeight(): 18 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 0 + GetRailType(): 0 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 37 + IsValidEngine(): true + GetName(): Armoured Van + GetCargoType(): 10 + CanRefitCargo(): false + GetCapacity(): 20 + GetReliability(): -1 + GetMaxSpeed(): 0 + GetPrice(): 1494 + GetMaxAge(): -1 + GetRunningCost(): 0 + GetPower(): -1 + GetWeight(): 30 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 0 + GetRailType(): 0 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 38 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 39 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 40 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 41 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 42 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 43 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 44 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 45 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 46 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 47 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 48 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 49 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 50 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 51 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 52 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 53 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 54 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 55 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 56 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 57 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 58 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 59 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 60 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 61 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 62 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 63 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 64 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 65 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 66 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 67 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 68 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 69 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 70 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 71 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 72 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 73 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 74 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 75 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 76 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 77 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 78 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 79 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 80 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 81 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 82 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 83 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 84 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 85 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 86 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 87 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 88 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 89 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 90 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 91 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 92 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 93 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 94 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 95 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 96 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 97 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 98 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 99 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 100 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 101 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 102 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 103 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 104 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 105 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 106 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 107 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 108 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 109 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 110 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 111 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 112 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 113 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 114 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 115 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 116 + IsValidEngine(): true + GetName(): MPS Regal Bus + GetCargoType(): 0 + CanRefitCargo(): false + GetCapacity(): 31 + GetReliability(): 78 + GetMaxSpeed(): 56 + GetPrice(): 4921 + GetMaxAge(): 4392 + GetRunningCost(): 426 + GetPower(): 90 + GetWeight(): 10 + GetMaxTractiveEffort(): 29 + GetVehicleType(): 1 + GetRailType(): 255 + GetRoadType(): 0 + GetPlaneType(): -1 + Engine 117 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 118 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 119 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 120 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 121 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 122 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 123 + IsValidEngine(): true + GetName(): Balogh Coal Truck + GetCargoType(): 1 + CanRefitCargo(): true + GetCapacity(): 20 + GetReliability(): 77 + GetMaxSpeed(): 48 + GetPrice(): 4429 + GetMaxAge(): 5490 + GetRunningCost(): 421 + GetPower(): 120 + GetWeight(): 9 + GetMaxTractiveEffort(): 26 + GetVehicleType(): 1 + GetRailType(): 255 + GetRoadType(): 0 + GetPlaneType(): -1 + Engine 124 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 125 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 126 + IsValidEngine(): true + GetName(): MPS Mail Truck + GetCargoType(): 2 + CanRefitCargo(): false + GetCapacity(): 22 + GetReliability(): 92 + GetMaxSpeed(): 48 + GetPrice(): 4716 + GetMaxAge(): 5490 + GetRunningCost(): 421 + GetPower(): 120 + GetWeight(): 9 + GetMaxTractiveEffort(): 26 + GetVehicleType(): 1 + GetRailType(): 255 + GetRoadType(): 0 + GetPlaneType(): -1 + Engine 127 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 128 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 129 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 130 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 131 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 132 + IsValidEngine(): true + GetName(): Witcombe Oil Tanker + GetCargoType(): 3 + CanRefitCargo(): false + GetCapacity(): 21 + GetReliability(): 98 + GetMaxSpeed(): 48 + GetPrice(): 4511 + GetMaxAge(): 5490 + GetRunningCost(): 421 + GetPower(): 120 + GetWeight(): 9 + GetMaxTractiveEffort(): 26 + GetVehicleType(): 1 + GetRailType(): 255 + GetRoadType(): 0 + GetPlaneType(): -1 + Engine 133 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 134 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 135 + IsValidEngine(): true + GetName(): Talbott Livestock Van + GetCargoType(): 4 + CanRefitCargo(): false + GetCapacity(): 14 + GetReliability(): 97 + GetMaxSpeed(): 48 + GetPrice(): 4306 + GetMaxAge(): 5490 + GetRunningCost(): 421 + GetPower(): 120 + GetWeight(): 9 + GetMaxTractiveEffort(): 26 + GetVehicleType(): 1 + GetRailType(): 255 + GetRoadType(): 0 + GetPlaneType(): -1 + Engine 136 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 137 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 138 + IsValidEngine(): true + GetName(): Balogh Goods Truck + GetCargoType(): 5 + CanRefitCargo(): false + GetCapacity(): 14 + GetReliability(): 87 + GetMaxSpeed(): 48 + GetPrice(): 4388 + GetMaxAge(): 5490 + GetRunningCost(): 421 + GetPower(): 120 + GetWeight(): 9 + GetMaxTractiveEffort(): 26 + GetVehicleType(): 1 + GetRailType(): 255 + GetRoadType(): 0 + GetPlaneType(): -1 + Engine 139 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 140 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 141 + IsValidEngine(): true + GetName(): Hereford Grain Truck + GetCargoType(): 6 + CanRefitCargo(): false + GetCapacity(): 20 + GetReliability(): 97 + GetMaxSpeed(): 48 + GetPrice(): 4675 + GetMaxAge(): 5490 + GetRunningCost(): 421 + GetPower(): 120 + GetWeight(): 9 + GetMaxTractiveEffort(): 26 + GetVehicleType(): 1 + GetRailType(): 255 + GetRoadType(): 0 + GetPlaneType(): -1 + Engine 142 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 143 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 144 + IsValidEngine(): true + GetName(): Witcombe Wood Truck + GetCargoType(): 7 + CanRefitCargo(): false + GetCapacity(): 20 + GetReliability(): 98 + GetMaxSpeed(): 48 + GetPrice(): 4839 + GetMaxAge(): 5490 + GetRunningCost(): 421 + GetPower(): 120 + GetWeight(): 9 + GetMaxTractiveEffort(): 26 + GetVehicleType(): 1 + GetRailType(): 255 + GetRoadType(): 0 + GetPlaneType(): -1 + Engine 145 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 146 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 147 + IsValidEngine(): true + GetName(): MPS Iron Ore Truck + GetCargoType(): 8 + CanRefitCargo(): false + GetCapacity(): 22 + GetReliability(): 97 + GetMaxSpeed(): 48 + GetPrice(): 4962 + GetMaxAge(): 5490 + GetRunningCost(): 421 + GetPower(): 120 + GetWeight(): 9 + GetMaxTractiveEffort(): 26 + GetVehicleType(): 1 + GetRailType(): 255 + GetRoadType(): 0 + GetPlaneType(): -1 + Engine 148 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 149 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 150 + IsValidEngine(): true + GetName(): Balogh Steel Truck + GetCargoType(): 9 + CanRefitCargo(): false + GetCapacity(): 15 + GetReliability(): 82 + GetMaxSpeed(): 48 + GetPrice(): 4593 + GetMaxAge(): 5490 + GetRunningCost(): 421 + GetPower(): 120 + GetWeight(): 9 + GetMaxTractiveEffort(): 26 + GetVehicleType(): 1 + GetRailType(): 255 + GetRoadType(): 0 + GetPlaneType(): -1 + Engine 151 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 152 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 153 + IsValidEngine(): true + GetName(): Balogh Armoured Truck + GetCargoType(): 10 + CanRefitCargo(): false + GetCapacity(): 12 + GetReliability(): 76 + GetMaxSpeed(): 48 + GetPrice(): 5947 + GetMaxAge(): 5490 + GetRunningCost(): 421 + GetPower(): 120 + GetWeight(): 9 + GetMaxTractiveEffort(): 26 + GetVehicleType(): 1 + GetRailType(): 255 + GetRoadType(): 0 + GetPlaneType(): -1 + Engine 154 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 155 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 156 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 157 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 158 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 159 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 160 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 161 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 162 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 163 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 164 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 165 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 166 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 167 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 168 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 169 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 170 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 171 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 172 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 173 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 174 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 175 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 176 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 177 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 178 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 179 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 180 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 181 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 182 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 183 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 184 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 185 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 186 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 187 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 188 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 189 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 190 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 191 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 192 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 193 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 194 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 195 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 196 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 197 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 198 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 199 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 200 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 201 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 202 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 203 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 204 + IsValidEngine(): true + GetName(): MPS Oil Tanker + GetCargoType(): 3 + CanRefitCargo(): false + GetCapacity(): 220 + GetReliability(): 99 + GetMaxSpeed(): 24 + GetPrice(): 30468 + GetMaxAge(): 10980 + GetRunningCost(): 2296 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 2 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 205 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 206 + IsValidEngine(): true + GetName(): MPS Passenger Ferry + GetCargoType(): 0 + CanRefitCargo(): false + GetCapacity(): 100 + GetReliability(): 88 + GetMaxSpeed(): 32 + GetPrice(): 18281 + GetMaxAge(): 10980 + GetRunningCost(): 1476 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 2 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 207 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 208 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 209 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 210 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 211 + IsValidEngine(): true + GetName(): Yate Cargo Ship + GetCargoType(): 5 + CanRefitCargo(): true + GetCapacity(): 160 + GetReliability(): 81 + GetMaxSpeed(): 24 + GetPrice(): 24375 + GetMaxAge(): 10980 + GetRunningCost(): 2460 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 2 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 212 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 213 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 214 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 215 + IsValidEngine(): true + GetName(): Sampson U52 + GetCargoType(): 0 + CanRefitCargo(): false + GetCapacity(): 25 + GetReliability(): 58 + GetMaxSpeed(): 236 + GetPrice(): 28710 + GetMaxAge(): 7320 + GetRunningCost(): 2390 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 3 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): 1 + Engine 216 + IsValidEngine(): true + GetName(): Coleman Count + GetCargoType(): 0 + CanRefitCargo(): false + GetCapacity(): 65 + GetReliability(): 95 + GetMaxSpeed(): 236 + GetPrice(): 30761 + GetMaxAge(): 8784 + GetRunningCost(): 2812 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 3 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): 1 + Engine 217 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 218 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 219 + IsValidEngine(): true + GetName(): Bakewell Cotswald LB-3 + GetCargoType(): 0 + CanRefitCargo(): false + GetCapacity(): 30 + GetReliability(): 77 + GetMaxSpeed(): 236 + GetPrice(): 30761 + GetMaxAge(): 10980 + GetRunningCost(): 2756 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 3 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): 1 + Engine 220 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 221 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 222 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 223 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 224 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 225 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 226 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 227 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 228 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 229 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 230 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 231 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 232 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 233 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 234 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 235 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 236 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 237 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 238 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 239 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 240 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 241 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 242 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 243 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 244 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 245 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 246 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 247 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 248 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 249 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 250 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 251 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 252 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 253 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 254 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 255 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Engine 256 + IsValidEngine(): false + GetName(): (null : 0x00000000) + GetCargoType(): 255 + CanRefitCargo(): false + GetCapacity(): -1 + GetReliability(): -1 + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxAge(): -1 + GetRunningCost(): -1 + GetPower(): -1 + GetWeight(): -1 + GetMaxTractiveEffort(): -1 + GetVehicleType(): 255 + GetRailType(): 255 + GetRoadType(): -1 + GetPlaneType(): -1 + Valid Engines: 31 + +--EngineList-- + Count(): 11 + CargoType ListDump: + 153 => 10 + 150 => 9 + 147 => 8 + 144 => 7 + 141 => 6 + 138 => 5 + 135 => 4 + 132 => 3 + 126 => 2 + 123 => 1 + 116 => 0 + Capacity ListDump: + 116 => 31 + 147 => 22 + 126 => 22 + 132 => 21 + 144 => 20 + 141 => 20 + 123 => 20 + 150 => 15 + 138 => 14 + 135 => 14 + 153 => 12 + Reliability ListDump: + 144 => 98 + 132 => 98 + 147 => 97 + 141 => 97 + 135 => 97 + 126 => 92 + 138 => 87 + 150 => 82 + 116 => 78 + 123 => 77 + 153 => 76 + MaxSpeed ListDump: + 116 => 56 + 153 => 48 + 150 => 48 + 147 => 48 + 144 => 48 + 141 => 48 + 138 => 48 + 135 => 48 + 132 => 48 + 126 => 48 + 123 => 48 + Price ListDump: + 153 => 5947 + 147 => 4962 + 116 => 4921 + 144 => 4839 + 126 => 4716 + 141 => 4675 + 150 => 4593 + 132 => 4511 + 123 => 4429 + 138 => 4388 + 135 => 4306 + +--Group-- + SetAutoReplace(): false + GetEngineReplacement(): 65535 + GetNumEngines(): 0 + AIRoad.BuildRoadDepot(): true + AIVehicle.BuildVehicle(): 12 + GetNumEngines(): 1 + CreateGroup(): 0 + MoveVehicle(): true + GetNumEngines(): 1 + GetNumEngines(): 1 + GetNumEngines(): 0 + GetName(): Group 0 + GetName(): (null : 0x00000000) + AIVehicle.SellVehicle(): true + AITile.DemolishTile(): true + HasWagonRemoval(): false + EnableWagonRemoval(): true + HasWagonRemoval(): true + EnableWagonRemoval(): true + EnableWagonRemoval(): true + HasWagonRemoval(): false + +--Industry-- + GetIndustryCount(): 71 + Industry 0 + IsValidIndustry(): true + GetName(): Kennville Oil Refinery + GetLocation(): 19695 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 0 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + Industry 1 + IsValidIndustry(): true + GetName(): Satown Forest + GetLocation(): 45122 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 72 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 2 + IsValidIndustry(): true + GetName(): Fudhattan Forest + GetLocation(): 41929 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 108 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 3 + IsValidIndustry(): true + GetName(): Beningville Forest + GetLocation(): 44640 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 80 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 4 + IsValidIndustry(): true + GetName(): Nefingbridge Forest + GetLocation(): 8793 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 135 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 5 + IsValidIndustry(): true + GetName(): Hutford Forest + GetLocation(): 55429 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 99 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 6 + IsValidIndustry(): true + GetName(): Great Hinninghall Forest + GetLocation(): 6533 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 72 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 7 + IsValidIndustry(): true + GetName(): Tonston Forest + GetLocation(): 27609 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 115 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 8 + IsValidIndustry(): true + GetName(): Planfield Sawmill + GetLocation(): 17318 + IsCargoAccepted(): 0 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + GetLastMonthProduction(): 0 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 9 + IsValidIndustry(): true + GetName(): Hutford Sawmill + GetLocation(): 60050 + IsCargoAccepted(): 0 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + GetLastMonthProduction(): 0 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 10 + IsValidIndustry(): true + GetName(): Natborough Sawmill + GetLocation(): 54184 + IsCargoAccepted(): 0 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + GetLastMonthProduction(): 0 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 11 + IsValidIndustry(): true + GetName(): Prundinghall Sawmill + GetLocation(): 48499 + IsCargoAccepted(): 0 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + GetLastMonthProduction(): 0 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 12 + IsValidIndustry(): true + GetName(): Fratston Sawmill + GetLocation(): 51419 + IsCargoAccepted(): 0 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + GetLastMonthProduction(): 0 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 13 + IsValidIndustry(): true + GetName(): Fort Frindston Sawmill + GetLocation(): 15950 + IsCargoAccepted(): 0 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + GetLastMonthProduction(): 0 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 14 + IsValidIndustry(): true + GetName(): Grinnway Sawmill + GetLocation(): 20001 + IsCargoAccepted(): 0 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + GetLastMonthProduction(): 0 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 15 + IsValidIndustry(): true + GetName(): Trenningville Coal Mine + GetLocation(): 51854 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 126 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 16 + IsValidIndustry(): true + GetName(): Kennville Coal Mine + GetLocation(): 11734 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 99 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 17 + IsValidIndustry(): true + GetName(): Great Hinninghall Coal Mine + GetLocation(): 13947 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 171 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 18 + IsValidIndustry(): true + GetName(): Little Frutford Coal Mine + GetLocation(): 23682 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 126 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 19 + IsValidIndustry(): true + GetName(): Hutford Coal Mine + GetLocation(): 57429 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 99 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 20 + IsValidIndustry(): true + GetName(): Mendston Coal Mine + GetLocation(): 8562 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 171 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 21 + IsValidIndustry(): true + GetName(): Tonston Coal Mine + GetLocation(): 29147 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 117 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 22 + IsValidIndustry(): true + GetName(): Quarfingfield Coal Mine + GetLocation(): 27822 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 153 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 23 + IsValidIndustry(): true + GetName(): Muningville Coal Mine + GetLocation(): 43035 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 90 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 24 + IsValidIndustry(): true + GetName(): Grinnway Coal Mine + GetLocation(): 17943 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 40 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 25 + IsValidIndustry(): true + GetName(): Satown Power Station + GetLocation(): 48182 + IsCargoAccepted(): 1 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + Industry 26 + IsValidIndustry(): true + GetName(): Tunford Power Station + GetLocation(): 33934 + IsCargoAccepted(): 1 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + Industry 27 + IsValidIndustry(): true + GetName(): Quarfingfield Power Station + GetLocation(): 23714 + IsCargoAccepted(): 1 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + Industry 28 + IsValidIndustry(): true + GetName(): Kennville Power Station + GetLocation(): 20170 + IsCargoAccepted(): 1 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + Industry 29 + IsValidIndustry(): true + GetName(): Nuntburg Power Station + GetLocation(): 6685 + IsCargoAccepted(): 1 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + Industry 30 + IsValidIndustry(): true + GetName(): Beburg Power Station + GetLocation(): 29022 + IsCargoAccepted(): 1 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + Industry 31 + IsValidIndustry(): true + GetName(): Beningville Power Station + GetLocation(): 44160 + IsCargoAccepted(): 1 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + Industry 32 + IsValidIndustry(): true + GetName(): Fort Frindston Oil Wells + GetLocation(): 14701 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 108 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 33 + IsValidIndustry(): true + GetName(): Nuntburg Oil Wells + GetLocation(): 5659 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 40 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 34 + IsValidIndustry(): true + GetName(): Beningville Oil Wells + GetLocation(): 36728 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 64 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 35 + IsValidIndustry(): true + GetName(): Grinnway Oil Wells + GetLocation(): 14361 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 63 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 36 + IsValidIndustry(): true + GetName(): Muningville Oil Wells + GetLocation(): 36908 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 72 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 37 + IsValidIndustry(): true + GetName(): Tonston Oil Wells + GetLocation(): 34237 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 108 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 38 + IsValidIndustry(): true + GetName(): Fort Frindston Iron Ore Mine + GetLocation(): 17742 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 108 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 39 + IsValidIndustry(): true + GetName(): Tonston Iron Ore Mine + GetLocation(): 25545 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 30 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 40 + IsValidIndustry(): true + GetName(): Fudhattan Iron Ore Mine + GetLocation(): 47838 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 72 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 41 + IsValidIndustry(): true + GetName(): Nuntburg Iron Ore Mine + GetLocation(): 8763 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 72 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 42 + IsValidIndustry(): true + GetName(): Larborough Iron Ore Mine + GetLocation(): 60866 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 81 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 43 + IsValidIndustry(): true + GetName(): Tunford Iron Ore Mine + GetLocation(): 41155 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 108 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 44 + IsValidIndustry(): true + GetName(): Chenfingbourne Iron Ore Mine + GetLocation(): 19529 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 135 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 45 + IsValidIndustry(): true + GetName(): Natborough Farm + GetLocation(): 52931 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 81 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): 81 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 46 + IsValidIndustry(): true + GetName(): Larborough Farm + GetLocation(): 59604 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 81 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): 50 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 47 + IsValidIndustry(): true + GetName(): Chenfingbourne Farm + GetLocation(): 24366 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 63 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): 30 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 48 + IsValidIndustry(): true + GetName(): Wruntown Farm + GetLocation(): 36847 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 72 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): 126 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 49 + IsValidIndustry(): true + GetName(): Little Frutford Farm + GetLocation(): 28287 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 90 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): 50 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 50 + IsValidIndustry(): true + GetName(): Hutford Farm + GetLocation(): 57432 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 117 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): 90 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 51 + IsValidIndustry(): true + GetName(): Tonston Farm + GetLocation(): 23519 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 81 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): 54 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 52 + IsValidIndustry(): true + GetName(): Nuntburg Farm + GetLocation(): 10773 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 126 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): 72 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 53 + IsValidIndustry(): true + GetName(): Satown Farm + GetLocation(): 48206 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 40 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): 40 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 54 + IsValidIndustry(): true + GetName(): Quarfingfield Farm + GetLocation(): 24005 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 72 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): 81 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + Industry 55 + IsValidIndustry(): true + GetName(): Little Frutford Steel Mill + GetLocation(): 21107 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 0 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + Industry 56 + IsValidIndustry(): true + GetName(): Quarfingfield Steel Mill + GetLocation(): 23727 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 0 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + Industry 57 + IsValidIndustry(): true + GetName(): Beburg Steel Mill + GetLocation(): 41813 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 0 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + Industry 58 + IsValidIndustry(): true + GetName(): Franinghead Steel Mill + GetLocation(): 8852 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 0 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + Industry 59 + IsValidIndustry(): true + GetName(): Larborough Steel Mill + GetLocation(): 59867 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 0 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + Industry 60 + IsValidIndustry(): true + GetName(): Satown Steel Mill + GetLocation(): 55360 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 0 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + Industry 61 + IsValidIndustry(): true + GetName(): Fratston Steel Mill + GetLocation(): 52953 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 0 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + Industry 62 + IsValidIndustry(): true + GetName(): Chenfingbourne Factory + GetLocation(): 24893 + IsCargoAccepted(): 0 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + GetLastMonthProduction(): 0 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + Industry 63 + IsValidIndustry(): true + GetName(): Fort Frindston Factory + GetLocation(): 20819 + IsCargoAccepted(): 0 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + GetLastMonthProduction(): 0 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + Industry 64 + IsValidIndustry(): true + GetName(): Fudhattan Factory + GetLocation(): 46278 + IsCargoAccepted(): 0 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + GetLastMonthProduction(): 0 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + Industry 65 + IsValidIndustry(): true + GetName(): Prundinghall Factory + GetLocation(): 53096 + IsCargoAccepted(): 0 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + GetLastMonthProduction(): 0 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + Industry 66 + IsValidIndustry(): true + GetName(): Kennville Factory + GetLocation(): 14818 + IsCargoAccepted(): 0 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + GetLastMonthProduction(): 0 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + Industry 67 + IsValidIndustry(): true + GetName(): Muningville Factory + GetLocation(): 34375 + IsCargoAccepted(): 0 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + GetLastMonthProduction(): 0 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + Industry 68 + IsValidIndustry(): true + GetName(): Trenningville Factory + GetLocation(): 44181 + IsCargoAccepted(): 0 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + GetLastMonthProduction(): 0 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + Industry 69 + IsValidIndustry(): true + GetName(): Wruntown Oil Refinery + GetLocation(): 39663 + IsCargoAccepted(): 0 + GetLastMonthProduction(): 0 + GetLastMonthTransported(): 0 + GetStockpiledCargo(): -1 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + Industry 70 + IsValidIndustry(): true + GetName(): Mendston Power Station + GetLocation(): 6498 + IsCargoAccepted(): 1 + GetLastMonthProduction(): -1 + GetLastMonthTransported(): -1 + GetStockpiledCargo(): 0 + Valid Industries: 71 + GetIndustryCount(): 71 + GetIndustryID(): 65535 + GetIndustryID(): 0 + +--IndustryList-- + Count(): 71 + Location ListDump: + 42 => 60866 + 9 => 60050 + 59 => 59867 + 46 => 59604 + 50 => 57432 + 19 => 57429 + 5 => 55429 + 60 => 55360 + 10 => 54184 + 65 => 53096 + 61 => 52953 + 45 => 52931 + 15 => 51854 + 12 => 51419 + 11 => 48499 + 53 => 48206 + 25 => 48182 + 40 => 47838 + 64 => 46278 + 1 => 45122 + 3 => 44640 + 68 => 44181 + 31 => 44160 + 23 => 43035 + 2 => 41929 + 57 => 41813 + 43 => 41155 + 69 => 39663 + 36 => 36908 + 48 => 36847 + 34 => 36728 + 67 => 34375 + 37 => 34237 + 26 => 33934 + 21 => 29147 + 30 => 29022 + 49 => 28287 + 22 => 27822 + 7 => 27609 + 39 => 25545 + 62 => 24893 + 47 => 24366 + 54 => 24005 + 56 => 23727 + 27 => 23714 + 18 => 23682 + 51 => 23519 + 55 => 21107 + 63 => 20819 + 28 => 20170 + 14 => 20001 + 0 => 19695 + 44 => 19529 + 24 => 17943 + 38 => 17742 + 8 => 17318 + 13 => 15950 + 66 => 14818 + 32 => 14701 + 35 => 14361 + 17 => 13947 + 16 => 11734 + 52 => 10773 + 58 => 8852 + 4 => 8793 + 41 => 8763 + 20 => 8562 + 29 => 6685 + 6 => 6533 + 70 => 6498 + 33 => 5659 + DistanceManhattanToTile(30000) ListDump: + 59 => 287 + 46 => 279 + 42 => 266 + 61 => 258 + 12 => 254 + 40 => 243 + 66 => 238 + 16 => 238 + 45 => 236 + 0 => 232 + 69 => 228 + 48 => 217 + 9 => 215 + 10 => 214 + 64 => 213 + 51 => 201 + 2 => 199 + 28 => 193 + 43 => 190 + 5 => 184 + 58 => 183 + 15 => 179 + 7 => 179 + 6 => 177 + 21 => 175 + 54 => 173 + 39 => 171 + 8 => 168 + 37 => 157 + 68 => 156 + 56 => 152 + 20 => 150 + 50 => 147 + 65 => 146 + 19 => 144 + 70 => 142 + 27 => 139 + 11 => 139 + 17 => 138 + 31 => 135 + 22 => 135 + 4 => 124 + 32 => 121 + 33 => 116 + 60 => 115 + 29 => 110 + 26 => 109 + 18 => 107 + 3 => 105 + 55 => 102 + 52 => 102 + 53 => 101 + 34 => 98 + 41 => 94 + 49 => 86 + 13 => 85 + 35 => 84 + 57 => 83 + 38 => 78 + 25 => 77 + 1 => 77 + 24 => 72 + 23 => 72 + 63 => 71 + 44 => 66 + 14 => 54 + 30 => 50 + 67 => 40 + 62 => 33 + 36 => 31 + 47 => 24 + DistanceSquareToTile(30000) ListDump: + 59 => 42697 + 46 => 40121 + 0 => 38162 + 69 => 37850 + 48 => 37157 + 61 => 36482 + 12 => 36130 + 42 => 35716 + 66 => 35284 + 40 => 35037 + 16 => 32740 + 51 => 31301 + 45 => 29530 + 21 => 29257 + 7 => 28661 + 64 => 26469 + 2 => 25525 + 28 => 25237 + 39 => 23733 + 43 => 23458 + 9 => 23293 + 10 => 23236 + 54 => 22777 + 37 => 20137 + 5 => 17026 + 58 => 16889 + 56 => 16754 + 8 => 16424 + 15 => 16061 + 22 => 15957 + 6 => 15689 + 27 => 13621 + 68 => 13226 + 50 => 13049 + 19 => 12818 + 20 => 11412 + 65 => 11236 + 70 => 10964 + 60 => 10057 + 11 => 9673 + 17 => 9594 + 33 => 9466 + 31 => 9425 + 26 => 9061 + 29 => 8642 + 4 => 8570 + 18 => 7349 + 32 => 7321 + 41 => 7010 + 52 => 6354 + 49 => 6290 + 53 => 5941 + 34 => 5860 + 55 => 5714 + 3 => 5553 + 25 => 5077 + 35 => 4250 + 13 => 3925 + 1 => 3805 + 57 => 3485 + 38 => 3204 + 23 => 3042 + 24 => 2834 + 63 => 2521 + 44 => 2306 + 30 => 2132 + 14 => 1746 + 67 => 818 + 36 => 745 + 62 => 569 + 47 => 488 + GetAmountOfStationsAround(30000) ListDump: + 70 => 0 + 69 => 0 + 68 => 0 + 67 => 0 + 66 => 0 + 65 => 0 + 64 => 0 + 63 => 0 + 62 => 0 + 61 => 0 + 60 => 0 + 59 => 0 + 58 => 0 + 57 => 0 + 56 => 0 + 55 => 0 + 54 => 0 + 53 => 0 + 52 => 0 + 51 => 0 + 50 => 0 + 49 => 0 + 48 => 0 + 47 => 0 + 46 => 0 + 45 => 0 + 44 => 0 + 43 => 0 + 42 => 0 + 41 => 0 + 40 => 0 + 39 => 0 + 38 => 0 + 37 => 0 + 36 => 0 + 35 => 0 + 34 => 0 + 33 => 0 + 32 => 0 + 31 => 0 + 30 => 0 + 29 => 0 + 28 => 0 + 27 => 0 + 26 => 0 + 25 => 0 + 24 => 0 + 23 => 0 + 22 => 0 + 21 => 0 + 20 => 0 + 19 => 0 + 18 => 0 + 17 => 0 + 16 => 0 + 15 => 0 + 14 => 0 + 13 => 0 + 12 => 0 + 11 => 0 + 10 => 0 + 9 => 0 + 8 => 0 + 7 => 0 + 6 => 0 + 5 => 0 + 4 => 0 + 3 => 0 + 2 => 0 + 1 => 0 + 0 => 0 + CargoAccepted(1) ListDump: + 70 => 1 + 31 => 1 + 30 => 1 + 29 => 1 + 28 => 1 + 27 => 1 + 26 => 1 + 25 => 1 + 69 => 0 + 68 => 0 + 67 => 0 + 66 => 0 + 65 => 0 + 64 => 0 + 63 => 0 + 62 => 0 + 61 => 0 + 60 => 0 + 59 => 0 + 58 => 0 + 57 => 0 + 56 => 0 + 55 => 0 + 54 => 0 + 53 => 0 + 52 => 0 + 51 => 0 + 50 => 0 + 49 => 0 + 48 => 0 + 47 => 0 + 46 => 0 + 45 => 0 + 44 => 0 + 43 => 0 + 42 => 0 + 41 => 0 + 40 => 0 + 39 => 0 + 38 => 0 + 37 => 0 + 36 => 0 + 35 => 0 + 34 => 0 + 33 => 0 + 32 => 0 + 24 => 0 + 23 => 0 + 22 => 0 + 21 => 0 + 20 => 0 + 19 => 0 + 18 => 0 + 17 => 0 + 16 => 0 + 15 => 0 + 14 => 0 + 13 => 0 + 12 => 0 + 11 => 0 + 10 => 0 + 9 => 0 + 8 => 0 + 7 => 0 + 6 => 0 + 5 => 0 + 4 => 0 + 3 => 0 + 2 => 0 + 1 => 0 + 0 => 0 +--IndustryList_CargoAccepting-- + Count(): 8 + Location ListDump: + 25 => 48182 + 31 => 44160 + 26 => 33934 + 30 => 29022 + 27 => 23714 + 28 => 20170 + 29 => 6685 + 70 => 6498 +--IndustryList_CargoProducing-- + Count(): 10 + Location ListDump: + 19 => 57429 + 15 => 51854 + 23 => 43035 + 21 => 29147 + 22 => 27822 + 18 => 23682 + 24 => 17943 + 17 => 13947 + 16 => 11734 + 20 => 8562 + +--IndustryTypeList-- + Count(): 12 + Location ListDump: + Id: 9 + IsRawIndustry(): true + ProductionCanIncrease(): true + GetConstructionCost(): -1 + GetName(): Farm + CanBuildIndustry(): false + CanProspectIndustry(): false + IsBuiltOnWater(): false + HasHeliport(): false + HasDock(): false + Id: 5 + IsRawIndustry(): true + ProductionCanIncrease(): true + GetConstructionCost(): -1 + GetName(): Oil Rig + CanBuildIndustry(): false + CanProspectIndustry(): false + IsBuiltOnWater(): true + HasHeliport(): true + HasDock(): true + Id: 12 + IsRawIndustry(): false + ProductionCanIncrease(): true + GetConstructionCost(): 747070 + GetName(): Bank + CanBuildIndustry(): true + CanProspectIndustry(): false + IsBuiltOnWater(): false + HasHeliport(): false + HasDock(): false + Id: 11 + IsRawIndustry(): true + ProductionCanIncrease(): false + GetConstructionCost(): -1 + GetName(): Oil Wells + CanBuildIndustry(): false + CanProspectIndustry(): false + IsBuiltOnWater(): false + HasHeliport(): false + HasDock(): false + Id: 1 + IsRawIndustry(): false + ProductionCanIncrease(): true + GetConstructionCost(): 703125 + GetName(): Power Station + CanBuildIndustry(): true + CanProspectIndustry(): false + IsBuiltOnWater(): false + HasHeliport(): false + HasDock(): false + Id: 3 + IsRawIndustry(): true + ProductionCanIncrease(): true + GetConstructionCost(): -1 + GetName(): Forest + CanBuildIndustry(): false + CanProspectIndustry(): false + IsBuiltOnWater(): false + HasHeliport(): false + HasDock(): false + Id: 2 + IsRawIndustry(): false + ProductionCanIncrease(): true + GetConstructionCost(): 656250 + GetName(): Sawmill + CanBuildIndustry(): true + CanProspectIndustry(): false + IsBuiltOnWater(): false + HasHeliport(): false + HasDock(): false + Id: 18 + IsRawIndustry(): true + ProductionCanIncrease(): true + GetConstructionCost(): -1 + GetName(): Iron Ore Mine + CanBuildIndustry(): false + CanProspectIndustry(): false + IsBuiltOnWater(): false + HasHeliport(): false + HasDock(): false + Id: 0 + IsRawIndustry(): true + ProductionCanIncrease(): true + GetConstructionCost(): -1 + GetName(): Coal Mine + CanBuildIndustry(): false + CanProspectIndustry(): false + IsBuiltOnWater(): false + HasHeliport(): false + HasDock(): false + Id: 8 + IsRawIndustry(): false + ProductionCanIncrease(): true + GetConstructionCost(): 629882 + GetName(): Steel Mill + CanBuildIndustry(): true + CanProspectIndustry(): false + IsBuiltOnWater(): false + HasHeliport(): false + HasDock(): false + Id: 4 + IsRawIndustry(): false + ProductionCanIncrease(): true + GetConstructionCost(): 714843 + GetName(): Oil Refinery + CanBuildIndustry(): true + CanProspectIndustry(): false + IsBuiltOnWater(): false + HasHeliport(): false + HasDock(): false + Id: 6 + IsRawIndustry(): false + ProductionCanIncrease(): true + GetConstructionCost(): 609375 + GetName(): Factory + CanBuildIndustry(): true + CanProspectIndustry(): false + IsBuiltOnWater(): false + HasHeliport(): false + HasDock(): false + +--Map-- + GetMapSize(): 65536 + GetMapSizeX(): 256 + GetMapSizeY(): 256 + GetTileX(123): 123 + GetTileY(123): 0 + GetTileIndex(): 123 + GetTileIndex(): 31488 + GetTileIndex(): 0 + GetTileIndex(): -257 + GetTileIndex(): 2570000 + IsValidTile(123): true + GetTileX(124): 124 + GetTileY(124): 0 + IsValidTile(124): true + IsValidTile(0): true + IsValidTile(-1): false + IsValidTile(): false + IsValidTile(): true + DemolishTile(): false + DemolishTile(): true + Distance + DistanceManhattan(): 54 + DistanceMax(): 39 + DistanceSquare(): 1746 + DistanceFromEdge(): 16 + +--AIMarine-- + IsWaterDepotTile(): false + IsDockTile(): false + IsBuoyTile(): false + IsLockTile(): false + IsCanalTile(): false + GetBankBalance(): 479851 + BuildWaterDepot(): true + BuildDock(): true + BuildBuoy(): true + BuildLock(): true + HasTransportType(): false + BuildCanal(): true + HasTransportType(): true + IsWaterDepotTile(): true + IsDockTile(): true + IsBuoyTile(): true + IsLockTile(): true + IsCanalTile(): true + GetBankBalance(): 465257 + +--AIWaypointList(BUOY)-- + Count(): 1 + Location ListDump: + 28481 + HasWaypointType: + false true false + + RemoveWaterDepot(): true + RemoveDock(): true + RemoveBuoy(): true + RemoveLock(): true + RemoveCanal(): true + IsWaterDepotTile(): false + IsDockTile(): false + IsBuoyTile(): false + IsLockTile(): false + IsCanalTile(): false + GetBankBalance(): 459862 + BuildWaterDepot(): true + BuildDock(): true + +--Prices-- + -Rail- + 0,BT_TRACK: 75 + 0,BT_SIGNAL: 48 + 0,BT_DEPOT: 450 + 0,BT_STATION: 285 + 0,BT_WAYPOINT: 450 + 1,BT_TRACK: -1 + 1,BT_SIGNAL: -1 + 1,BT_DEPOT: -1 + 1,BT_STATION: -1 + 1,BT_WAYPOINT: -1 + -Road- + ROADTYPE_ROAD,BT_ROAD: 71 + ROADTYPE_ROAD,BT_DEPOT: 375 + ROADTYPE_ROAD,BT_BUS_STOP: 150 + ROADTYPE_ROAD,BT_TRUCK_STOP: 150 + ROADTYPE_TRAM,BT_ROAD: -1 + ROADTYPE_TRAM,BT_DEPOT: -1 + ROADTYPE_TRAM,BT_BUS_STOP: -1 + ROADTYPE_TRAM,BT_TRUCK_STOP: -1 + -Water- + BT_DOCK: 262 + BT_DEPOT: 525 + BT_BUOY: 262 + -Tile- + BT_FOUNDATION: 187 + BT_TERRAFORM: 187 + BT_BUILD_TREES: 15 + BT_CLEAR_GRASS: 15 + BT_CLEAR_ROUGH: 30 + BT_CLEAR_ROCKY: 150 + BT_CLEAR_FIELDS: 375 + BT_CLEAR_HOUSE: 1200 + +--Rail-- + IsRailTile(): false + BuildRailTrack(): true + BuildSignal(): true + RemoveRailTrack(): false + RemoveRailTrack(): true + BuildRail(): true + HasTransportType(): true + HasTransportType(): false + RemoveRail(): true + Depot + IsRailTile(): false + BuildRailDepot(): false + BuildRailDepot(): false + BuildRailDepot(): true + BuildRailDepot(): false + GetRailDepotFrontTile(): 33412 + IsBuildable(): false + DepotList + Count(): 1 + Depot distance from (0,0) ListDump: + 33411 => 261 + RemoveDepot(): true + BuildRailDepot(): true + Station + BuildRailStation(): false + BuildRailStation(): true + IsRailStationTile(): false + IsRailStationTile(): true + IsRailStationTile(): true + RemoveRailStationTileRectangle():true + IsRailStationTile(): false + IsRailStationTile(): true + IsRailStationTile(): false + DemolishTile(): true + IsRailStationTile(): false + IsRailStationTile(): false + IsRailStationTile(): false + +--RailTypeList-- + Count(): 1 + ListDump: + RailType: 0 + GetName(): Railway construction + IsRailTypeAvailable(): true + GetMaxSpeed(): 0 + +--Road-- + Road + IsRoadTile(): false + BuildRoad(): false + BuildRoad(): false + HasTransportType(): false + BuildRoad(): true + HasTransportType(): true + AreRoadTilesConnected(): true + IsRoadTile(): true + HasRoadType(Road): true + HasRoadType(Tram): false + GetNeighbourRoadCount(): 2 + RemoveRoad(): false + RemoveRoad(): true + RemoveRoad(): false + RemoveRoad(): true + BuildOneWayRoad(): true + AreRoadTilesConnected(): true + AreRoadTilesConnected(): false + BuildOneWayRoad(): true + AreRoadTilesConnected(): false + AreRoadTilesConnected(): false + BuildOneWayRoad(): true + BuildOneWayRoad(): true + AreRoadTilesConnected(): true + AreRoadTilesConnected(): true + RemoveRoad(): true + IsRoadTypeAvailable(Road): true + IsRoadTypeAvailable(Tram): false + SetCurrentRoadType(Tram): (null : 0x00000000) + GetCurrentRoadType(): 0 + Depot + IsRoadTile(): false + BuildRoadDepot(): false + BuildRoadDepot(): false + BuildRoadDepot(): true + BuildRoadDepot(): false + HasRoadType(Road): true + HasRoadType(Tram): false + GetLastError(): 260 + GetLastErrorString(): ERR_AREA_NOT_CLEAR + GetErrorCategory(): 1 + IsRoadTile(): false + GetRoadDepotFrontTile(): 33412 + IsRoadDepotTile(): true + IsBuildable(): false + DepotList + Count(): 1 + Depot distance from (0,0) ListDump: + 33411 => 261 + RemoveRoadDepot(): true + RemoveRoadDepot(): false + Station + IsRoadTile(): false + BuildRoadStation(): false + BuildRoadStation(): false + BuildRoadStation(): true + BuildRoadStation(): true + IsStationTile(): true + IsStationTile(): false + HasRoadType(Road): true + HasRoadType(Tram): false + IsRoadTile(): false + GetDriveThroughBackTile(): -1 + GetRoadStationFrontTile(): 33412 + IsRoadStationTile(): true + IsDriveThroughRoadStationTile: false + RemoveRoadStation(): true + RemoveRoadStation(): false + Station Types + BuildRoadStation(bus): true + BuildRoadStation(truck): true + BuildRoadStation(truck): true + BuildRoadStation(bus): true + BuildRoadStation(truck): true + BuildDriveThroughRoadStation(bus-drive): true + BuildDriveThroughRoadStation(truck-drive): true + BuildDriveThroughRoadStation(bus-drive): true + BuildDriveThroughRoadStation(truck-drive): true + BuildRoadDepot(): true + GetRoadStationFrontTile(): 33411 + GetRoadStationFrontTile(): 33924 + IsDriveThroughRoadStationTile: true + IsBuildable(): false + GetDriveThroughBackTile(): 33416 + GetRoadStationFrontTile(): 33414 + IsRoadTile(): true + +--Sign-- + BuildSign(33410, 'Some Sign'): 0 + BuildSign(33411, 'Test'): 1 + SetName(1, 'Test2'): true + BuildSign(33409, 'Some other Sign'): 2 + RemoveSign(2): true + + Sign 0 + IsValidSign(): true + GetName(): Some Sign + GetLocation(): 33410 + Sign 1 + IsValidSign(): true + GetName(): Test2 + GetLocation(): 33411 + Valid Signs: 2 + +--Station-- + IsValidStation(0): true + IsValidStation(1000): false + GetName(0): Beningville Airport + SetName(0): true + GetName(0): Look, a station + GetLocation(1): 29253 + GetLocation(1000): -1 + GetStationID(33411): 4 + GetStationID(34411): 65535 + GetStationID(33411): 4 + HasRoadType(3, TRAM): false + HasRoadType(3, ROAD): false + HasRoadType(33411, TRAM): false + HasRoadType(33411, ROAD): true + HasStationType(3, BUS): false + HasStationType(3, TRAIN): false + GetCoverageRadius(BUS): 3 + GetCoverageRadius(TRUCK): 3 + GetCoverageRadius(TRAIN): 4 + GetNearestTown(): 15 + GetNearestTown(): 65535 + GetNearestTown(): 10 + +--CargoWaiting-- + GetCargoWaiting(0, 0): 0 + GetCargoWaitingFrom(0, 0, 0): 0 + GetCargoWaitingVia(0, 0, 0): 0 + GetCargoWaitingFromVia(0, 0, 0, 0): 0 + GetCargoWaitingFromVia(0, 0, 1000, 0): -1 + GetCargoWaitingFrom(0, 1000, 0): -1 + GetCargoWaitingVia(0, 1000, 0): -1 + GetCargoWaitingFromVia(0, 1000, 0, 0): -1 + GetCargoWaitingFromVia(0, 1000, 1000, 0): -1 + GetCargoWaiting(1000, 0): -1 + GetCargoWaitingFrom(1000, 0, 0): -1 + GetCargoWaitingVia(1000, 0, 0): -1 + GetCargoWaitingFromVia(1000, 0, 0, 0): -1 + GetCargoWaitingFromVia(1000, 0, 1000, 0): -1 + GetCargoWaitingFrom(1000, 1000, 0): -1 + GetCargoWaitingVia(1000, 1000, 0): -1 + GetCargoWaitingFromVia(1000, 1000, 0, 0): -1 + GetCargoWaitingFromVia(1000, 1000, 1000, 0): -1 + GetCargoWaiting(0, 1000): -1 + GetCargoWaitingFrom(0, 0, 1000): -1 + GetCargoWaitingVia(0, 0, 1000): -1 + GetCargoWaitingFromVia(0, 0, 0, 1000): -1 + GetCargoWaitingFromVia(0, 0, 1000, 1000): -1 + GetCargoWaitingFrom(0, 1000, 1000): -1 + GetCargoWaitingVia(0, 1000, 1000): -1 + GetCargoWaitingFromVia(0, 1000, 0, 1000): -1 + GetCargoWaitingFromVia(0, 1000, 1000, 1000): -1 + GetCargoWaiting(1000, 1000): -1 + GetCargoWaitingFrom(1000, 0, 1000): -1 + GetCargoWaitingVia(1000, 0, 1000): -1 + GetCargoWaitingFromVia(1000, 0, 0, 1000): -1 + GetCargoWaitingFromVia(1000, 0, 1000, 1000): -1 + GetCargoWaitingFrom(1000, 1000, 1000): -1 + GetCargoWaitingVia(1000, 1000, 1000): -1 + GetCargoWaitingFromVia(1000, 1000, 0, 1000): -1 + GetCargoWaitingFromVia(1000, 1000, 1000, 1000): -1 + +--CargoPlanned-- + GetCargoPlanned(0, 0): 0 + GetCargoPlannedFrom(0, 0, 0): 0 + GetCargoPlannedVia(0, 0, 0): 0 + GetCargoPlannedFromVia(0, 0, 0, 0): 0 + GetCargoPlannedFromVia(0, 0, 1000, 0): -1 + GetCargoPlannedFrom(0, 1000, 0): -1 + GetCargoPlannedVia(0, 1000, 0): -1 + GetCargoPlannedFromVia(0, 1000, 0, 0): -1 + GetCargoPlannedFromVia(0, 1000, 1000, 0): -1 + GetCargoPlanned(1000, 0): -1 + GetCargoPlannedFrom(1000, 0, 0): -1 + GetCargoPlannedVia(1000, 0, 0): -1 + GetCargoPlannedFromVia(1000, 0, 0, 0): -1 + GetCargoPlannedFromVia(1000, 0, 1000, 0): -1 + GetCargoPlannedFrom(1000, 1000, 0): -1 + GetCargoPlannedVia(1000, 1000, 0): -1 + GetCargoPlannedFromVia(1000, 1000, 0, 0): -1 + GetCargoPlannedFromVia(1000, 1000, 1000, 0): -1 + GetCargoPlanned(0, 1000): -1 + GetCargoPlannedFrom(0, 0, 1000): -1 + GetCargoPlannedVia(0, 0, 1000): -1 + GetCargoPlannedFromVia(0, 0, 0, 1000): -1 + GetCargoPlannedFromVia(0, 0, 1000, 1000): -1 + GetCargoPlannedFrom(0, 1000, 1000): -1 + GetCargoPlannedVia(0, 1000, 1000): -1 + GetCargoPlannedFromVia(0, 1000, 0, 1000): -1 + GetCargoPlannedFromVia(0, 1000, 1000, 1000): -1 + GetCargoPlanned(1000, 1000): -1 + GetCargoPlannedFrom(1000, 0, 1000): -1 + GetCargoPlannedVia(1000, 0, 1000): -1 + GetCargoPlannedFromVia(1000, 0, 0, 1000): -1 + GetCargoPlannedFromVia(1000, 0, 1000, 1000): -1 + GetCargoPlannedFrom(1000, 1000, 1000): -1 + GetCargoPlannedVia(1000, 1000, 1000): -1 + GetCargoPlannedFromVia(1000, 1000, 0, 1000): -1 + GetCargoPlannedFromVia(1000, 1000, 1000, 1000): -1 + +--Tile-- + HasTreeOnTile(): false + IsFarmTile(): true + IsRockTile(): true + IsRoughTile(): true + HasTreeOnTile(): true + IsFarmTile(): false + IsRockTile(): false + IsRoughTile(): false + IsSnowTile(): false + IsDesertTile(): false + PlantTree(): true + HasTreeOnTile(): true + PlantTree(): false + HasTreeOnTile(): false + PlantTreeRectangle(): true + HasTreeOnTile(): true + +--TileList-- + Count(): 0 + Count(): 9 + Slope(): done + Count(): 9 + ListDump: + 27631 => 29 + 27631 => 65535 + 27631 => true + 27631 => false + 27888 => 13 + 27888 => 2 + 27888 => false + 27888 => false + 27376 => 12 + 27376 => 3 + 27376 => false + 27376 => false + 27375 => 12 + 27375 => 3 + 27375 => false + 27375 => false + 27889 => 9 + 27889 => 6 + 27889 => false + 27889 => false + 27887 => 8 + 27887 => 7 + 27887 => false + 27887 => false + 27632 => 8 + 27632 => 7 + 27632 => false + 27632 => false + 27633 => 0 + 27633 => 15 + 27633 => false + 27633 => false + 27377 => 0 + 27377 => 15 + 27377 => false + 27377 => false + +--TileList-- + Count(): 0 + Count(): 27 + Height(): done + Count(): 27 + ListDump: + 34956 => 4 + 34700 => 4 + 34444 => 4 + 34955 => 3 + 34954 => 3 + 34953 => 3 + 34699 => 3 + 34698 => 3 + 34697 => 3 + 34693 => 3 + 34692 => 3 + 34443 => 3 + 34442 => 3 + 34441 => 3 + 34439 => 3 + 34438 => 3 + 34437 => 3 + 34436 => 3 + 34952 => 2 + 34951 => 2 + 34950 => 2 + 34949 => 2 + 34948 => 2 + 34696 => 2 + 34695 => 2 + 34694 => 2 + 34440 => 2 + CornerHeight(North): done + Count(): 27 + ListDump: + 34956 => 4 + 34700 => 4 + 34444 => 4 + 34955 => 3 + 34954 => 3 + 34953 => 3 + 34699 => 3 + 34698 => 3 + 34697 => 3 + 34693 => 3 + 34692 => 3 + 34443 => 3 + 34442 => 3 + 34441 => 3 + 34439 => 3 + 34438 => 3 + 34437 => 3 + 34436 => 3 + 34952 => 2 + 34951 => 2 + 34950 => 2 + 34949 => 2 + 34948 => 2 + 34696 => 2 + 34695 => 2 + 34694 => 2 + 34440 => 2 + MinHeight(): done + Count(): 27 + ListDump: + 34956 => 4 + 34700 => 4 + 34444 => 4 + 34955 => 3 + 34954 => 3 + 34953 => 3 + 34699 => 3 + 34698 => 3 + 34697 => 3 + 34443 => 3 + 34442 => 3 + 34441 => 3 + 34436 => 3 + 34952 => 2 + 34951 => 2 + 34950 => 2 + 34949 => 2 + 34948 => 2 + 34696 => 2 + 34695 => 2 + 34694 => 2 + 34693 => 2 + 34692 => 2 + 34440 => 2 + 34439 => 2 + 34438 => 2 + 34437 => 2 + MaxHeight(): done + Count(): 27 + ListDump: + 34956 => 4 + 34955 => 4 + 34700 => 4 + 34699 => 4 + 34444 => 4 + 34443 => 4 + 34954 => 3 + 34953 => 3 + 34952 => 3 + 34951 => 3 + 34950 => 3 + 34949 => 3 + 34948 => 3 + 34698 => 3 + 34697 => 3 + 34696 => 3 + 34693 => 3 + 34692 => 3 + 34442 => 3 + 34441 => 3 + 34440 => 3 + 34439 => 3 + 34438 => 3 + 34437 => 3 + 34436 => 3 + 34695 => 2 + 34694 => 2 + Slope(): done + KeepValue(0): done + Count(): 12 + ListDump: + 34956 => 0 + 34954 => 0 + 34953 => 0 + 34700 => 0 + 34698 => 0 + 34697 => 0 + 34695 => 0 + 34694 => 0 + 34444 => 0 + 34442 => 0 + 34441 => 0 + 34436 => 0 + Buildable(): done + KeepValue(1): done + Count(): 35 + BuildableRectangle(3, 3) ListDump: + 42415 => 1 + 42414 => 1 + 42413 => 1 + 42412 => 1 + 42411 => 1 + 42410 => 1 + 42159 => 1 + 42158 => 1 + 42157 => 1 + 42156 => 1 + 42155 => 1 + 42154 => 1 + 41903 => 1 + 41902 => 1 + 41901 => 1 + 41900 => 1 + 41899 => 1 + 41898 => 1 + 41647 => 1 + 41646 => 1 + 41645 => 1 + 41644 => 1 + 41643 => 1 + 41642 => 1 + 41641 => 1 + 41391 => 1 + 41390 => 1 + 41389 => 1 + 41388 => 1 + 41387 => 1 + 41386 => 1 + 41385 => 1 + 42153 => 0 + 41897 => 0 + 41384 => 0 + DistanceManhattanToTile(30000) ListDump: + 42415 => 175 + 42414 => 174 + 42159 => 174 + 42413 => 173 + 42158 => 173 + 41903 => 173 + 42412 => 172 + 42157 => 172 + 41902 => 172 + 41647 => 172 + 42411 => 171 + 42156 => 171 + 41901 => 171 + 41646 => 171 + 41391 => 171 + 42410 => 170 + 42155 => 170 + 41900 => 170 + 41645 => 170 + 41390 => 170 + 42154 => 169 + 41899 => 169 + 41644 => 169 + 41389 => 169 + 42153 => 168 + 41898 => 168 + 41643 => 168 + 41388 => 168 + 41897 => 167 + 41642 => 167 + 41387 => 167 + 41641 => 166 + 41386 => 166 + 41385 => 165 + 41384 => 164 + DistanceSquareToTile(30000) ListDump: + 42415 => 18433 + 42159 => 18338 + 41903 => 18245 + 42414 => 18180 + 41647 => 18154 + 42158 => 18085 + 41391 => 18065 + 41902 => 17992 + 42413 => 17929 + 41646 => 17901 + 42157 => 17834 + 41390 => 17812 + 41901 => 17741 + 42412 => 17680 + 41645 => 17650 + 42156 => 17585 + 41389 => 17561 + 41900 => 17492 + 42411 => 17433 + 41644 => 17401 + 42155 => 17338 + 41388 => 17312 + 41899 => 17245 + 42410 => 17188 + 41643 => 17154 + 42154 => 17093 + 41387 => 17065 + 41898 => 17000 + 41642 => 16909 + 42153 => 16850 + 41386 => 16820 + 41897 => 16757 + 41641 => 16666 + 41385 => 16577 + 41384 => 16336 + GetOwner() ListDump: + 42415 => -1 + 42414 => -1 + 42413 => -1 + 42412 => -1 + 42411 => -1 + 42410 => -1 + 42159 => -1 + 42158 => -1 + 42157 => -1 + 42156 => -1 + 42155 => -1 + 42154 => -1 + 42153 => -1 + 41903 => -1 + 41902 => -1 + 41901 => -1 + 41900 => -1 + 41899 => -1 + 41898 => -1 + 41897 => -1 + 41647 => -1 + 41646 => -1 + 41645 => -1 + 41644 => -1 + 41643 => -1 + 41642 => -1 + 41641 => -1 + 41391 => -1 + 41390 => -1 + 41389 => -1 + 41388 => -1 + 41387 => -1 + 41386 => -1 + 41385 => -1 + 41384 => -1 + 33183 => -1 + 33182 => -1 + 33181 => -1 + 33180 => -1 + 33179 => -1 + 33178 => -1 + 33177 => -1 + 33176 => -1 + 33175 => -1 + 32927 => -1 + 32926 => -1 + 32925 => -1 + 32924 => -1 + 32923 => -1 + 32922 => -1 + 32921 => -1 + 32920 => -1 + 32919 => -1 + 32671 => -1 + 32670 => -1 + 32669 => -1 + 32668 => -1 + 32667 => -1 + 32666 => -1 + 32665 => -1 + 32664 => -1 + 32663 => -1 + 32415 => -1 + 32414 => -1 + 32413 => -1 + 32412 => -1 + 32411 => -1 + 32410 => -1 + 32409 => -1 + 32408 => -1 + 32407 => -1 + 32159 => -1 + 32158 => -1 + 32157 => -1 + 32156 => -1 + 32155 => -1 + 32154 => -1 + 32153 => -1 + 32152 => -1 + 32151 => -1 + 31903 => -1 + 31902 => -1 + 31901 => -1 + 31900 => -1 + 31899 => -1 + 31898 => -1 + 31897 => -1 + 31896 => -1 + 31895 => -1 + 31647 => -1 + 31646 => -1 + 31645 => -1 + 31644 => -1 + 31643 => -1 + 31642 => -1 + 31641 => -1 + 31640 => -1 + 31639 => -1 + 31391 => -1 + 31390 => -1 + 31389 => -1 + 31388 => -1 + 31387 => -1 + 31386 => -1 + 31385 => -1 + 31384 => -1 + 31383 => -1 + 31135 => -1 + 31134 => -1 + 31133 => -1 + 31132 => -1 + 31131 => -1 + 31130 => -1 + 31129 => -1 + 31128 => -1 + 31127 => -1 + 30879 => -1 + 30878 => -1 + 30877 => -1 + 30876 => -1 + 30875 => -1 + 30874 => -1 + 30873 => -1 + 30872 => -1 + 30871 => -1 + 30623 => -1 + 30622 => -1 + 30621 => -1 + 30620 => -1 + 30619 => -1 + 30618 => -1 + 30617 => -1 + 30616 => -1 + 30615 => -1 + GetTownAuthority() ListDump: + 33183 => 65535 + 33182 => 65535 + 33181 => 65535 + 33180 => 65535 + 33179 => 65535 + 33178 => 65535 + 33177 => 65535 + 33176 => 65535 + 33175 => 65535 + 32927 => 65535 + 32926 => 65535 + 32925 => 65535 + 32924 => 65535 + 32923 => 65535 + 32922 => 65535 + 32921 => 65535 + 32920 => 65535 + 32919 => 65535 + 32671 => 65535 + 32670 => 65535 + 32669 => 65535 + 32668 => 65535 + 32667 => 65535 + 32666 => 65535 + 32665 => 65535 + 32664 => 65535 + 32663 => 65535 + 32415 => 65535 + 32414 => 65535 + 32413 => 65535 + 32412 => 65535 + 32411 => 65535 + 32410 => 65535 + 32409 => 65535 + 32408 => 65535 + 32407 => 65535 + 32159 => 65535 + 32158 => 65535 + 32157 => 65535 + 32156 => 65535 + 32155 => 65535 + 32154 => 65535 + 32153 => 65535 + 32152 => 65535 + 32151 => 65535 + 31903 => 65535 + 31902 => 65535 + 31901 => 65535 + 31900 => 65535 + 31899 => 65535 + 31898 => 65535 + 31897 => 65535 + 31896 => 65535 + 31895 => 65535 + 31647 => 65535 + 31646 => 65535 + 31645 => 65535 + 31644 => 65535 + 31643 => 65535 + 31642 => 65535 + 31641 => 65535 + 31640 => 65535 + 31639 => 65535 + 31391 => 65535 + 31390 => 65535 + 31389 => 65535 + 31388 => 65535 + 31387 => 65535 + 31386 => 65535 + 31385 => 65535 + 31384 => 65535 + 31383 => 65535 + 31135 => 65535 + 31134 => 65535 + 31133 => 65535 + 31132 => 65535 + 31131 => 65535 + 31130 => 65535 + 31129 => 65535 + 31128 => 65535 + 31127 => 65535 + 30879 => 65535 + 30878 => 65535 + 30877 => 65535 + 30876 => 65535 + 30875 => 65535 + 30874 => 65535 + 30873 => 65535 + 30872 => 65535 + 30871 => 65535 + 30623 => 65535 + 30622 => 65535 + 30621 => 65535 + 30620 => 65535 + 30619 => 65535 + 30618 => 65535 + 30617 => 65535 + 30616 => 65535 + 30615 => 65535 + 42415 => 3 + 42414 => 3 + 42413 => 3 + 42412 => 3 + 42411 => 3 + 42410 => 3 + 42159 => 3 + 42158 => 3 + 42157 => 3 + 42156 => 3 + 42155 => 3 + 42154 => 3 + 42153 => 3 + 41903 => 3 + 41902 => 3 + 41901 => 3 + 41900 => 3 + 41899 => 3 + 41898 => 3 + 41897 => 3 + 41647 => 3 + 41646 => 3 + 41645 => 3 + 41644 => 3 + 41643 => 3 + 41642 => 3 + 41641 => 3 + 41391 => 3 + 41390 => 3 + 41389 => 3 + 41388 => 3 + 41387 => 3 + 41386 => 3 + 41385 => 3 + 41384 => 3 + GetClosestTown() ListDump: + 31127 => 24 + 30872 => 24 + 30871 => 24 + 30617 => 24 + 30616 => 24 + 30615 => 24 + 42415 => 3 + 42414 => 3 + 42413 => 3 + 42412 => 3 + 42411 => 3 + 42410 => 3 + 42159 => 3 + 42158 => 3 + 42157 => 3 + 42156 => 3 + 42155 => 3 + 42154 => 3 + 42153 => 3 + 41903 => 3 + 41902 => 3 + 41901 => 3 + 41900 => 3 + 41899 => 3 + 41898 => 3 + 41897 => 3 + 41647 => 3 + 41646 => 3 + 41645 => 3 + 41644 => 3 + 41643 => 3 + 41642 => 3 + 41641 => 3 + 41391 => 3 + 41390 => 3 + 41389 => 3 + 41388 => 3 + 41387 => 3 + 41386 => 3 + 41385 => 3 + 41384 => 3 + 33183 => 3 + 33182 => 3 + 33181 => 3 + 33180 => 3 + 33179 => 3 + 33178 => 3 + 33177 => 3 + 33176 => 3 + 33175 => 3 + 32927 => 3 + 32926 => 3 + 32925 => 3 + 32924 => 3 + 32923 => 3 + 32922 => 3 + 32921 => 3 + 32920 => 3 + 32919 => 3 + 32671 => 3 + 32670 => 3 + 32669 => 3 + 32668 => 3 + 32667 => 3 + 32666 => 3 + 32665 => 3 + 32664 => 3 + 32663 => 3 + 32415 => 3 + 32414 => 3 + 32413 => 3 + 32412 => 3 + 32411 => 3 + 32410 => 3 + 32409 => 3 + 32408 => 3 + 32407 => 3 + 32159 => 3 + 32158 => 3 + 32157 => 3 + 32156 => 3 + 32155 => 3 + 32154 => 3 + 32153 => 3 + 32152 => 3 + 32151 => 3 + 31903 => 3 + 31902 => 3 + 31901 => 3 + 31900 => 3 + 31899 => 3 + 31898 => 3 + 31897 => 3 + 31896 => 3 + 31895 => 3 + 31647 => 3 + 31646 => 3 + 31645 => 3 + 31644 => 3 + 31643 => 3 + 31642 => 3 + 31641 => 3 + 31640 => 3 + 31639 => 3 + 31391 => 3 + 31390 => 3 + 31389 => 3 + 31388 => 3 + 31387 => 3 + 31386 => 3 + 31385 => 3 + 31384 => 3 + 31383 => 3 + 31135 => 3 + 31134 => 3 + 31133 => 3 + 31132 => 3 + 31131 => 3 + 31130 => 3 + 31129 => 3 + 31128 => 3 + 30879 => 3 + 30878 => 3 + 30877 => 3 + 30876 => 3 + 30875 => 3 + 30874 => 3 + 30873 => 3 + 30623 => 3 + 30622 => 3 + 30621 => 3 + 30620 => 3 + 30619 => 3 + 30618 => 3 + CargoAcceptance(): done + KeepAboveValue(10): done + Count(): 15 + ListDump: + 41897 => 29 + 41385 => 26 + 41384 => 26 + 42153 => 25 + 41641 => 23 + 41899 => 17 + 41898 => 17 + 41387 => 17 + 41386 => 17 + 41643 => 14 + 41642 => 14 + 42411 => 13 + 42410 => 13 + 42155 => 13 + 42154 => 13 + RoadTile(): done + KeepValue(1): done + Count(): 0 + ListDump: + NeighbourRoadCount():done + KeepValue(1): done + Count(): 0 + ListDump: + Water(): done + Count(): 45 + ListDump: + 54941 => 1 + 54940 => 1 + 54939 => 1 + 54938 => 1 + 54937 => 1 + 54936 => 1 + 54935 => 1 + 54934 => 1 + 54933 => 1 + 54685 => 1 + 54684 => 1 + 54683 => 1 + 54682 => 1 + 54681 => 1 + 54680 => 1 + 54679 => 1 + 54678 => 1 + 54677 => 1 + 54429 => 1 + 54428 => 1 + 54427 => 1 + 54426 => 1 + 54425 => 1 + 54424 => 1 + 54423 => 1 + 54422 => 1 + 54421 => 1 + 54173 => 1 + 54172 => 1 + 54171 => 1 + 54170 => 1 + 54169 => 1 + 54168 => 0 + 54167 => 0 + 54166 => 0 + 54165 => 0 + 53917 => 0 + 53916 => 0 + 53915 => 0 + 53914 => 0 + 53913 => 0 + 53912 => 0 + 53911 => 0 + 53910 => 0 + 53909 => 0 + +--TileList_IndustryAccepting-- + Count(): 47 + Location ListDump: + 21234 => 16 + 21233 => 16 + 21232 => 16 + 21231 => 16 + 21230 => 16 + 21229 => 16 + 20978 => 16 + 20977 => 16 + 20976 => 16 + 20975 => 16 + 20974 => 16 + 20973 => 16 + 20722 => 16 + 20718 => 16 + 20717 => 16 + 20466 => 16 + 20462 => 16 + 20461 => 16 + 20210 => 16 + 20206 => 16 + 20205 => 16 + 19954 => 16 + 19950 => 16 + 19949 => 16 + 21490 => 8 + 21489 => 8 + 21488 => 8 + 21487 => 8 + 21486 => 8 + 21485 => 8 + 21484 => 8 + 21235 => 8 + 21228 => 8 + 20979 => 8 + 20972 => 8 + 20723 => 8 + 20716 => 8 + 20467 => 8 + 20460 => 8 + 20211 => 8 + 20204 => 8 + 19955 => 8 + 19948 => 8 + 19699 => 8 + 19698 => 8 + 19694 => 8 + 19693 => 8 + +--TileList_IndustryProducing-- + Count(): 92 + Location ListDump: + 46920 => 1 + 46919 => 1 + 46918 => 1 + 46917 => 1 + 46916 => 1 + 46915 => 1 + 46914 => 1 + 46913 => 1 + 46912 => 1 + 46911 => 1 + 46664 => 1 + 46663 => 1 + 46662 => 1 + 46661 => 1 + 46660 => 1 + 46659 => 1 + 46658 => 1 + 46657 => 1 + 46656 => 1 + 46655 => 1 + 46408 => 1 + 46407 => 1 + 46406 => 1 + 46405 => 1 + 46404 => 1 + 46403 => 1 + 46402 => 1 + 46401 => 1 + 46400 => 1 + 46399 => 1 + 46152 => 1 + 46151 => 1 + 46150 => 1 + 46149 => 1 + 46146 => 1 + 46145 => 1 + 46144 => 1 + 46143 => 1 + 45896 => 1 + 45895 => 1 + 45894 => 1 + 45889 => 1 + 45888 => 1 + 45887 => 1 + 45640 => 1 + 45639 => 1 + 45638 => 1 + 45633 => 1 + 45632 => 1 + 45631 => 1 + 45384 => 1 + 45383 => 1 + 45382 => 1 + 45377 => 1 + 45376 => 1 + 45375 => 1 + 45128 => 1 + 45127 => 1 + 45126 => 1 + 45121 => 1 + 45120 => 1 + 45119 => 1 + 44872 => 1 + 44871 => 1 + 44870 => 1 + 44869 => 1 + 44868 => 1 + 44867 => 1 + 44866 => 1 + 44865 => 1 + 44864 => 1 + 44863 => 1 + 44616 => 1 + 44615 => 1 + 44614 => 1 + 44613 => 1 + 44612 => 1 + 44611 => 1 + 44610 => 1 + 44609 => 1 + 44608 => 1 + 44607 => 1 + 44360 => 1 + 44359 => 1 + 44358 => 1 + 44357 => 1 + 44356 => 1 + 44355 => 1 + 44354 => 1 + 44353 => 1 + 44352 => 1 + 44351 => 1 + +--TileList_StationType-- + Count(): 4 + Location ListDump: + 33667 => 0 + 33415 => 0 + 33413 => 0 + 33411 => 0 + +--Town-- + GetTownCount(): 28 + Town 0 + IsValidTown(): true + GetName(): Planfield + GetPopulation(): 787 + GetLocation(): 15508 + GetHouseCount(): 30 + GetRating(): 0 + IsCity(): true + Town 1 + IsValidTown(): true + GetName(): Trenningville + GetPopulation(): 243 + GetLocation(): 46751 + GetHouseCount(): 17 + GetRating(): 0 + IsCity(): false + Town 2 + IsValidTown(): true + GetName(): Tonston + GetPopulation(): 380 + GetLocation(): 28365 + GetHouseCount(): 19 + GetRating(): 0 + IsCity(): false + Town 3 + IsValidTown(): true + GetName(): Tunford + GetPopulation(): 176 + GetLocation(): 41895 + GetHouseCount(): 11 + GetRating(): 0 + IsCity(): false + Town 4 + IsValidTown(): true + GetName(): Wruntown + GetPopulation(): 426 + GetLocation(): 41450 + GetHouseCount(): 18 + GetRating(): 0 + IsCity(): true + Town 5 + IsValidTown(): true + GetName(): Fratston + GetPopulation(): 205 + GetLocation(): 55007 + GetHouseCount(): 11 + GetRating(): 0 + IsCity(): false + Town 6 + IsValidTown(): true + GetName(): Muningville + GetPopulation(): 679 + GetLocation(): 38200 + GetHouseCount(): 28 + GetRating(): 0 + IsCity(): false + Town 7 + IsValidTown(): true + GetName(): Hutford + GetPopulation(): 950 + GetLocation(): 59234 + GetHouseCount(): 33 + GetRating(): 0 + IsCity(): false + Town 8 + IsValidTown(): true + GetName(): Satown + GetPopulation(): 358 + GetLocation(): 51267 + GetHouseCount(): 20 + GetRating(): 0 + IsCity(): true + Town 9 + IsValidTown(): true + GetName(): Frindinghattan + GetPopulation(): 478 + GetLocation(): 5825 + GetHouseCount(): 18 + GetRating(): 0 + IsCity(): false + Town 10 + IsValidTown(): true + GetName(): Nuntburg + GetPopulation(): 737 + GetLocation(): 6446 + GetHouseCount(): 26 + GetRating(): 6 + IsCity(): false + Town 11 + IsValidTown(): true + GetName(): Fort Frindston + GetPopulation(): 180 + GetLocation(): 14935 + GetHouseCount(): 13 + GetRating(): 0 + IsCity(): false + Town 12 + IsValidTown(): true + GetName(): Gintborough + GetPopulation(): 982 + GetLocation(): 32740 + GetHouseCount(): 28 + GetRating(): 0 + IsCity(): true + Town 13 + IsValidTown(): true + GetName(): Great Hinninghall + GetPopulation(): 310 + GetLocation(): 9595 + GetHouseCount(): 14 + GetRating(): 0 + IsCity(): false + Town 14 + IsValidTown(): true + GetName(): Prundinghall + GetPopulation(): 432 + GetLocation(): 51298 + GetHouseCount(): 18 + GetRating(): 0 + IsCity(): false + Town 15 + IsValidTown(): true + GetName(): Beningville + GetPopulation(): 807 + GetLocation(): 42338 + GetHouseCount(): 33 + GetRating(): 6 + IsCity(): false + Town 16 + IsValidTown(): true + GetName(): Kennville + GetPopulation(): 780 + GetLocation(): 17345 + GetHouseCount(): 33 + GetRating(): 0 + IsCity(): true + Town 17 + IsValidTown(): true + GetName(): Quarfingfield + GetPopulation(): 218 + GetLocation(): 24252 + GetHouseCount(): 13 + GetRating(): 0 + IsCity(): false + Town 18 + IsValidTown(): true + GetName(): Nefingbridge + GetPopulation(): 262 + GetLocation(): 10574 + GetHouseCount(): 13 + GetRating(): 0 + IsCity(): false + Town 19 + IsValidTown(): true + GetName(): Mendston + GetPopulation(): 243 + GetLocation(): 6511 + GetHouseCount(): 14 + GetRating(): 0 + IsCity(): false + Town 20 + IsValidTown(): true + GetName(): Chenfingbourne + GetPopulation(): 437 + GetLocation(): 22585 + GetHouseCount(): 15 + GetRating(): 6 + IsCity(): true + Town 21 + IsValidTown(): true + GetName(): Franinghead + GetPopulation(): 802 + GetLocation(): 9634 + GetHouseCount(): 27 + GetRating(): 0 + IsCity(): false + Town 22 + IsValidTown(): true + GetName(): Natborough + GetPopulation(): 221 + GetLocation(): 51891 + GetHouseCount(): 12 + GetRating(): 0 + IsCity(): false + Town 23 + IsValidTown(): true + GetName(): Larborough + GetPopulation(): 652 + GetLocation(): 59622 + GetHouseCount(): 27 + GetRating(): 0 + IsCity(): false + Town 24 + IsValidTown(): true + GetName(): Little Frutford + GetPopulation(): 668 + GetLocation(): 19596 + GetHouseCount(): 34 + GetRating(): 4 + IsCity(): true + Town 25 + IsValidTown(): true + GetName(): Grinnway + GetPopulation(): 563 + GetLocation(): 16433 + GetHouseCount(): 15 + GetRating(): 0 + IsCity(): false + Town 26 + IsValidTown(): true + GetName(): Beburg + GetPopulation(): 362 + GetLocation(): 39505 + GetHouseCount(): 18 + GetRating(): 0 + IsCity(): false + Town 27 + IsValidTown(): true + GetName(): Fudhattan + GetPopulation(): 390 + GetLocation(): 45525 + GetHouseCount(): 19 + GetRating(): 0 + IsCity(): false + Valid Towns: 28 + GetTownCount(): 28 + +--TownList-- + Count(): 28 + Location ListDump: + 23 => 59622 + 7 => 59234 + 5 => 55007 + 22 => 51891 + 14 => 51298 + 8 => 51267 + 1 => 46751 + 27 => 45525 + 15 => 42338 + 3 => 41895 + 4 => 41450 + 26 => 39505 + 6 => 38200 + 12 => 32740 + 2 => 28365 + 17 => 24252 + 20 => 22585 + 24 => 19596 + 16 => 17345 + 25 => 16433 + 0 => 15508 + 11 => 14935 + 18 => 10574 + 21 => 9634 + 13 => 9595 + 19 => 6511 + 10 => 6446 + 9 => 5825 + DistanceManhattanToTile(30000) ListDump: + 23 => 297 + 5 => 272 + 9 => 240 + 4 => 230 + 27 => 225 + 22 => 216 + 16 => 195 + 21 => 194 + 12 => 190 + 1 => 176 + 3 => 165 + 7 => 164 + 2 => 164 + 17 => 163 + 0 => 157 + 19 => 155 + 13 => 155 + 24 => 133 + 14 => 133 + 18 => 106 + 8 => 102 + 15 => 98 + 11 => 98 + 10 => 94 + 26 => 70 + 25 => 54 + 6 => 40 + 20 => 38 + DistanceSquareToTile(30000) ListDump: + 23 => 46349 + 5 => 40034 + 4 => 36532 + 12 => 32500 + 27 => 30825 + 9 => 30050 + 2 => 24698 + 22 => 24386 + 16 => 23525 + 17 => 20129 + 21 => 19396 + 1 => 16546 + 3 => 16277 + 7 => 15496 + 0 => 13249 + 19 => 12433 + 13 => 12025 + 24 => 10145 + 14 => 9389 + 10 => 8468 + 8 => 7250 + 18 => 6676 + 11 => 5002 + 15 => 4804 + 25 => 2810 + 26 => 2458 + 6 => 1088 + 20 => 922 + IsWithinTownInfluence(15508) ListDump: + 0 => 1 + 27 => 0 + 26 => 0 + 25 => 0 + 24 => 0 + 23 => 0 + 22 => 0 + 21 => 0 + 20 => 0 + 19 => 0 + 18 => 0 + 17 => 0 + 16 => 0 + 15 => 0 + 14 => 0 + 13 => 0 + 12 => 0 + 11 => 0 + 10 => 0 + 9 => 0 + 8 => 0 + 7 => 0 + 6 => 0 + 5 => 0 + 4 => 0 + 3 => 0 + 2 => 0 + 1 => 0 + GetAllowedNoise() ListDump: + 27 => 2 + 26 => 2 + 25 => 2 + 24 => 2 + 23 => 2 + 22 => 2 + 21 => 2 + 20 => 2 + 19 => 2 + 18 => 2 + 17 => 2 + 16 => 2 + 14 => 2 + 13 => 2 + 12 => 2 + 11 => 2 + 10 => 2 + 9 => 2 + 8 => 2 + 7 => 2 + 6 => 2 + 5 => 2 + 4 => 2 + 3 => 2 + 2 => 2 + 1 => 2 + 0 => 2 + 15 => 1 + KeepAboveValue(500): done + Count(): 11 + Population ListDump: + 12 => 982 + 7 => 950 + 15 => 807 + 21 => 802 + 0 => 787 + 16 => 780 + 10 => 737 + 6 => 679 + 24 => 668 + 23 => 652 + 25 => 563 + HasStatue(): false + GetRoadReworkDuration(): 0 + GetExclusiveRightsCompany(): -1 + GetExclusiveRightsDuration(): 0 + IsActionAvailable(BUILD_STATUE): true + PerformTownAction(BUILD_STATUE): true + IsActionAvailable(BUILD_STATUE): false + HasStatue(): true + +--Tunnel-- + IsTunnelTile(): false + RemoveTunnel(): false + GetOtherTunnelEnd(): 28026 + BuildTunnel(): true + GetOtherTunnelEnd(): 28026 + IsTunnelTile(): true + IsTunnelTile(): true + RemoveTunnel(): true + IsTunnelTile(): false + --Errors-- + BuildTunnel(): true + BuildTunnel(): false + GetLastErrorString(): ERR_TUNNEL_ANOTHER_TUNNEL_IN_THE_WAY + RemoveTunnel(): true + +--Vehicle-- + IsValidVehicle(-1): false + IsValidVehicle(0): false + IsValidVehicle(12): false + ISValidVehicle(9999): false + BuildVehicle(): 12 + IsValidVehicle(12): true + CloneVehicle(): 13 + --Accounting-- + GetCosts(): 11894 + Should be: 11894 + ResetCosts(): (null : 0x00000000) + SellVehicle(13): true + IsInDepot(): true + IsStoppedInDepot(): true + StartStopVehicle(): true + IsInDepot(): false + IsStoppedInDepot(): false + SendVehicleToDepot(): true + IsInDepot(): false + IsStoppedInDepot(): false + --Accounting-- + GetCosts(): -5947 + Should be: -5947 + GetName(): Road Vehicle 1 + SetName(): true + GetName(): MyVehicleName + CloneVehicle(): 13 + --VehicleData-- + GetLocation(): 33417 + GetEngineType(): 153 + GetUnitNumber(): 1 + GetAge(): 0 + GetMaxAge(): 5490 + GetAgeLeft(): 5490 + GetCurrentSpeed(): 7 + GetRunningCost(): 421 + GetProfitThisYear(): 0 + GetProfitLastYear(): 0 + GetCurrentValue(): 5947 + GetVehicleType(): 1 + GetRoadType(): 0 + GetCapacity(): 12 + GetCargoLoad(): 0 + IsInDepot(): false + GetNumWagons(): 1 + GetWagonEngineType(): 153 + GetWagonAge(): 0 + GetLength(): 8 + GetOwner(): 1 + BuildVehicle(): 14 + IsValidVehicle(14): true + IsInDepot(14): true + IsStoppedInDepot(14): true + IsValidVehicle(15): false + IsInDepot(15): false + IsStoppedInDepot(15): false + BuildVehicle(): 16 + IsValidVehicle(16): true + IsInDepot(16): true + IsStoppedInDepot(16): true + BuildRailDepot(): true + BuildVehicle(): 17 + BuildVehicle(): 18 + BuildVehicle(): 19 + MoveWagonChain(): true + GetNumWagons(): 3 + GetLength(): 24 + GetWagonEngineType(): 9 + GetWagonAge(): 1 + GetWagonEngineType(): 27 + GetWagonAge(): 1 + GetWagonEngineType(): 27 + GetWagonAge(): 0 + GetWagonEngineType(): 65535 + GetWagonAge(): -1 + --Errors-- + RefitVehicle(): false + GetLastErrorString(): ERR_VEHICLE_NOT_IN_DEPOT + SellVehicle(): false + GetLastErrorString(): ERR_VEHICLE_NOT_IN_DEPOT + SendVehicleToDepot(): false + GetLastErrorString(): ERR_UNKNOWN + +--VehicleList-- + Count(): 5 + Location ListDump: + 13 => 33417 + 12 => 33417 + 14 => 32119 + 16 => 28479 + 17 => 10008 + EngineType ListDump: + 14 => 219 + 16 => 204 + 13 => 153 + 12 => 153 + 17 => 9 + UnitNumber ListDump: + 13 => 2 + 17 => 1 + 16 => 1 + 14 => 1 + 12 => 1 + Age ListDump: + 17 => 1 + 16 => 1 + 14 => 1 + 13 => 1 + 12 => 1 + MaxAge ListDump: + 16 => 10980 + 14 => 10980 + 17 => 7320 + 13 => 5490 + 12 => 5490 + AgeLeft ListDump: + 16 => 10979 + 14 => 10979 + 17 => 7319 + 13 => 5489 + 12 => 5489 + CurrentSpeed ListDump: + 12 => 21 + 17 => 0 + 16 => 0 + 14 => 0 + 13 => 0 + RunningCost ListDump: + 14 => 2756 + 17 => 2296 + 16 => 2296 + 13 => 421 + 12 => 421 + ProfitThisYear ListDump: + 17 => 0 + 16 => 0 + 14 => 0 + 13 => 0 + 12 => -1 + ProfitLastYear ListDump: + 17 => 0 + 16 => 0 + 14 => 0 + 13 => 0 + 12 => 0 + CurrentValue ListDump: + 14 => 30761 + 16 => 30468 + 17 => 22265 + 13 => 5947 + 12 => 5947 + VehicleType ListDump: + 14 => 3 + 16 => 2 + 13 => 1 + 12 => 1 + 17 => 0 + RoadType ListDump: + 13 => 0 + 12 => 0 + 17 => -1 + 16 => -1 + 14 => -1 + VehicleType ListDump: + 13 => 12 + 12 => 12 + 17 => 0 + 16 => 0 + 14 => 0 + VehicleType ListDump: + 17 => 0 + 16 => 0 + 14 => 0 + 13 => 0 + 12 => 0 + +--Order-- + GetOrderCount(): 0 + GetOrderDestination(): -1 + AreOrderFlagsValid(): true + AreOrderFlagsValid(): false + AreOrderFlagsValid(): true + AreOrderFlagsValid(): true + AreOrderFlagsValid(): true + AreOrderFlagsValid(): true + IsValidConditionalOrder(): true + IsValidConditionalOrder(): false + IsValidConditionalOrder(): true + IsValidConditionalOrder(): false + IsValidVehicleOrder(): false + IsGotoStationOrder(): false + IsGotoDepotOrder(): false + IsGotoWaypointOrder(): false + IsConditionalOrder(): false + IsCurrentOrderPartOfOrderList(): false + GetOrderFlags(): 65535 + AppendOrder(): true + InsertOrder(): true + GetOrderCount(): 2 + IsValidVehicleOrder(): true + IsGotoStationOrder(): true + IsGotoDepotOrder(): false + IsGotoWaypointOrder(): false + IsConditionalOrder(): false + IsCurrentOrderPartOfOrderList(): false + GetOrderFlags(): 8 + GetOrderFlags(): 8 + GetOrderJumpTo(): -1 + RemoveOrder(): true + SetOrderFlags(): true + GetOrderFlags(): 64 + GetOrderDestination(): 33411 + CopyOrders(): false + CopyOrders(): true + ShareOrders(): false + ShareOrders(): true + UnshareOrders(): true + AppendOrder(): true + GetStopLocation(): -1 + BuildVehicle(): 20 + BuildRailStation(): true + AppendOrder(): true + GetOrderCount(): 1 + GetStopLocation(): 2 + SetStopLocation(): true + GetStopLocation(): 1 + +--VehicleList_Station-- + Count(): 1 + Location ListDump: + 20 => 23596 + foreach(): + 20 => 23596 + + First Subsidy Test + --Subsidy (0) -- + IsValidSubsidy(): true + IsAwarded(): false + GetAwardedTo(): -1 + GetExpireDate(): 714080 + GetSourceType(): 1 + GetSourceIndex(): 15 + GetDestinationType(): 1 + GetDestinationIndex(): 7 + GetCargoType(): 0 + IsEventWaiting: false + +--Math-- + -2147483648 < -2147483647: true + -2147483648 < -1 : true + -2147483648 < 0 : true + -2147483648 < 1 : true + -2147483648 < 2147483647: true + -2147483647 < -2147483648: false + -1 < -2147483648: false + 0 < -2147483648: false + 1 < -2147483648: false + 2147483647 < -2147483648: false + -1 > 2147483647: false + -1 > 1 : false + -1 > 0 : false + -1 > -1 : false + -1 > -2147483648: true + 1 > 2147483647: false + 1 > 1 : false + 1 > 0 : true + 1 > -1 : true + 1 > -2147483648: true + 2147483647 > 2147483646: true + 2147483647 > 1 : true + 2147483647 > 0 : true + 2147483647 > -1 : true + 2147483647 > -2147483648: true + 2147483646 > 2147483647: false + 1 > 2147483647: false + 0 > 2147483647: false + -1 > 2147483647: false + -2147483648 > 2147483647: false + 13725 > -2147483648: true +ERROR: The script died unexpectedly. diff --git a/bin/ai/regression/tst_stationlist/main.nut b/bin/ai/regression/tst_stationlist/main.nut new file mode 100644 index 0000000..60f3e4a --- /dev/null +++ b/bin/ai/regression/tst_stationlist/main.nut @@ -0,0 +1,216 @@ +/* $Id$ */ + +class Regression extends AIController { + function Start(); +}; + + +function Regression::StationList() +{ + local list = AIStationList(AIStation.STATION_BUS_STOP + AIStation.STATION_TRUCK_STOP); + + print(""); + print("--StationList--"); + print(" Count(): " + list.Count()); + list.Valuate(AIStation.GetLocation); + print(" Location ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIStation.GetCargoWaiting, 0); + print(" CargoWaiting(0) ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIStation.GetCargoWaiting, 1); + print(" CargoWaiting(1) ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } +}; + +function Regression::StationList_Cargo() +{ + print(""); + print("--StationList_Cargo--"); + + for (local mode = AIStationList_Cargo.CM_WAITING; mode <= AIStationList_Cargo.CM_PLANNED; ++mode) { + print(" " + mode); + for (local selector = AIStationList_Cargo.CS_BY_FROM; selector <= AIStationList_Cargo.CS_FROM_BY_VIA ; ++selector) { + print(" " + selector); + local list = AIStationList_Cargo(mode, selector, 6, 0, 7); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + } + } +}; + +function Regression::StationList_CargoPlanned() +{ + print(""); + print("--StationList_CargoPlanned--"); + + for (local selector = AIStationList_Cargo.CS_BY_FROM; selector <= AIStationList_Cargo.CS_FROM_BY_VIA; ++selector) { + print(" " + selector); + local list = AIStationList_CargoPlanned(selector, 6, 0, 7); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + } +}; + +function Regression::StationList_CargoPlannedByFrom() +{ + print(""); + print("--StationList_CargoPlannedByFrom--"); + local list = AIStationList_CargoPlannedByFrom(2, 0); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } +}; + +function Regression::StationList_CargoPlannedByVia() +{ + print(""); + print("--StationList_CargoPlannedByVia--"); + local list = AIStationList_CargoPlannedByVia(2, 0); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } +}; + +function Regression::StationList_CargoPlannedViaByFrom() +{ + print(""); + print("--StationList_CargoPlannedViaByFrom--"); + local list = AIStationList_CargoPlannedViaByFrom(6, 0, 7); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } +}; + +function Regression::StationList_CargoPlannedFromByVia() +{ + print(""); + print("--StationList_CargoPlannedFromByVia--"); + local list = AIStationList_CargoPlannedFromByVia(6, 0, 7); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } +}; + +function Regression::StationList_CargoWaiting() +{ + print(""); + print("--StationList_CargoWaiting--"); + + for (local selector = AIStationList_Cargo.CS_BY_FROM; selector <= AIStationList_Cargo.CS_FROM_BY_VIA; ++selector) { + print(" " + selector); + local list = AIStationList_CargoWaiting(selector, 6, 0, 7); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + } +}; + +function Regression::StationList_CargoWaitingByFrom() +{ + print(""); + print("--StationList_CargoWaitingByFrom--"); + local list = AIStationList_CargoWaitingByFrom(2, 0); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } +}; + +function Regression::StationList_CargoWaitingByVia() +{ + print(""); + print("--StationList_CargoWaitingByVia--"); + local list = AIStationList_CargoWaitingByVia(2, 0); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } +}; + +function Regression::StationList_CargoWaitingViaByFrom() +{ + print(""); + print("--StationList_CargoWaitingViaByFrom--"); + local list = AIStationList_CargoWaitingViaByFrom(6, 0, 7); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } +}; + +function Regression::StationList_CargoWaitingFromByVia() +{ + print(""); + print("--StationList_CargoWaitingFromByVia--"); + local list = AIStationList_CargoWaitingFromByVia(2, 0, 2); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } +}; + +function Regression::StationList_Vehicle() +{ + local list = AIStationList_Vehicle(12); + + print(""); + print("--StationList_Vehicle--"); + print(" Count(): " + list.Count()); + list.Valuate(AIStation.GetLocation); + print(" Location ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIStation.GetCargoWaiting, 0); + print(" CargoWaiting(0) ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIStation.GetCargoWaiting, 1); + print(" CargoWaiting(1) ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIStation.GetCargoRating, 1); + print(" CargoRating(1) ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIStation.GetDistanceManhattanToTile, 30000); + print(" DistanceManhattanToTile(30000) ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIStation.GetDistanceSquareToTile, 30000); + print(" DistanceSquareToTile(30000) ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } + list.Valuate(AIStation.IsWithinTownInfluence, 0); + print(" IsWithinTownInfluence(0) ListDump:"); + for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { + print(" " + i + " => " + list.GetValue(i)); + } +} + +function Regression::Start() +{ + StationList(); + StationList_Cargo(); + StationList_CargoPlanned(); + StationList_CargoPlannedByFrom(); + StationList_CargoPlannedByVia(); + StationList_CargoPlannedViaByFrom(); + StationList_CargoPlannedFromByVia(); + StationList_CargoWaiting(); + StationList_CargoWaitingByFrom(); + StationList_CargoWaitingByVia(); + StationList_CargoWaitingViaByFrom(); + StationList_CargoWaitingFromByVia(); + StationList_Vehicle(); +} diff --git a/bin/ai/regression/tst_stationlist/result.txt b/bin/ai/regression/tst_stationlist/result.txt new file mode 100644 index 0000000..20e5947 --- /dev/null +++ b/bin/ai/regression/tst_stationlist/result.txt @@ -0,0 +1,127 @@ + +--StationList-- + Count(): 5 + Location ListDump: + 6 => 42341 + 2 => 41831 + 7 => 41825 + 5 => 33421 + 4 => 33411 + CargoWaiting(0) ListDump: + 7 => 6 + 6 => 6 + 2 => 3 + 5 => 0 + 4 => 0 + CargoWaiting(1) ListDump: + 7 => 0 + 6 => 0 + 5 => 0 + 4 => 0 + 2 => 0 + +--StationList_Cargo-- + 0 + 0 + 6 => 6 + 1 + 6 => 2 + 2 + 2 => 4 + 7 => 2 + 3 + 1 + 0 + 7 => 18 + 6 => 16 + 2 => 7 + 1 + 6 => 8 + 2 => 3 + 2 + 2 => 16 + 6 => 14 + 7 => 11 + 3 + 6 => 10 + 2 => 8 + +--StationList_CargoPlanned-- + 0 + 7 => 18 + 6 => 16 + 2 => 7 + 1 + 6 => 8 + 2 => 3 + 2 + 2 => 16 + 6 => 14 + 7 => 11 + 3 + 6 => 10 + 2 => 8 + +--StationList_CargoPlannedByFrom-- + 7 => 8 + 6 => 8 + 2 => 7 + +--StationList_CargoPlannedByVia-- + 2 => 16 + 6 => 7 + +--StationList_CargoPlannedViaByFrom-- + 6 => 8 + 2 => 3 + +--StationList_CargoPlannedFromByVia-- + 6 => 10 + 2 => 8 + +--StationList_CargoWaiting-- + 0 + 6 => 6 + 1 + 6 => 2 + 2 + 2 => 4 + 7 => 2 + 3 + +--StationList_CargoWaitingByFrom-- + 2 => 3 + +--StationList_CargoWaitingByVia-- + 6 => 3 + +--StationList_CargoWaitingViaByFrom-- + 6 => 2 + +--StationList_CargoWaitingFromByVia-- + 6 => 3 + +--StationList_Vehicle-- + Count(): 2 + Location ListDump: + 5 => 33421 + 4 => 33411 + CargoWaiting(0) ListDump: + 5 => 0 + 4 => 0 + CargoWaiting(1) ListDump: + 5 => 0 + 4 => 0 + CargoRating(1) ListDump: + 5 => -1 + 4 => -1 + DistanceManhattanToTile(30000) ListDump: + 5 => 106 + 4 => 96 + DistanceSquareToTile(30000) ListDump: + 5 => 8818 + 4 => 7058 + IsWithinTownInfluence(0) ListDump: + 5 => 0 + 4 => 0 +ERROR: The script died unexpectedly. diff --git a/bin/ai/regression/tst_stationlist/test.sav b/bin/ai/regression/tst_stationlist/test.sav new file mode 100644 index 0000000..ef551c7 Binary files /dev/null and b/bin/ai/regression/tst_stationlist/test.sav differ diff --git a/bin/baseset/no_music.obm b/bin/baseset/no_music.obm new file mode 100644 index 0000000..f782d23 --- /dev/null +++ b/bin/baseset/no_music.obm @@ -0,0 +1,99 @@ +; $Id$ +; +; This represents more or less nothingness +; +[metadata] +name = NoMusic +shortname = NULL +version = 0 +fallback = true +description = A music pack without actual music. +description.af_ZA = 'n Musiek stel sonder enige musiek. +description.ar_EG = مجموعة موسيقى بدون موسيقى +description.be_BY = "ПуÑты" набор музычнага афармленнÑ, Ñкі не зьмÑшчае ніÑкай музыкі. +description.bg_BG = Празен музикален пакет. +description.ca_ES = Un joc de música sense cap música. +description.cs_CZ = Prázná hudební sada. +description.cy_GB = Pecyn cerddoriaeth heb unrhyw gerddoriaeth ynddo. +description.da_DK = En musikpakke uden musik. +description.de_DE = Ein Musikset ohne Musik. +description.el_GR = Ένα πάκετο μουσικής χωÏίς Ï€Ïαγματική μουσική. +description.en_AU = A music pack without actual music. +description.en_US = A music pack without actual music. +description.es_ES = Un conjunto de música vacío. +description.et_EE = Muusikakogu ilma muusikata. +description.fi_FI = Musiikkipaketti, jossa ei ole musiikkia. +description.fr_FR = Un pack de musiques sans musiques. +description.ga_IE = Pacáiste ceoil gan aon cheol iarbhír ann. +description.gd_GB = Pacaid ciùil anns nach eil fonn sam bith. +description.gl_ES = Un conxunto de músicas sen ningunha música. +description.hr_HR = MuziÄki paket bez ikakve muzike. +description.hu_HU = Zenei alapcsomag zene nélkül. +description.id_ID = Paket musik tanpa musik sungguhan. +description.is_IS = Tónlistarpakki sem er í raun án tónlistar. +description.it_IT = Un pacchetto musicale non contenente alcuna musica. +description.ja_JP = 空ã®éŸ³æ¥½ãƒ‘ック +description.ko_KR = 실제 ìŒì•…ì´ ì—†ëŠ” ìŒì•… 목ë¡ìž…니다. +description.la_VA = Sarcina musicae sine ulla musica. +description.lb_LU = E Musikpack ouni aktuell Musik. +description.lt_LT = Muzikos pakas be muzikos. +description.lv_LV = MÅ«zikas kopa bez mÅ«zikas +description.nb_NO = En musikkpakke uten noe musikk. +description.nl_NL = Een muziekset zonder muziek. +description.nn_NO = Ei musikkpakke utan noko musikk. +description.pl_PL = Zestaw utworów muzycznych nie zawierajÄ…cy żadnej muzyki. +description.pt_BR = Um pacote de músicas sem músicas. +description.pt_PT = Um conjunto de música vazio. +description.ro_RO = Un set de muzică fără muzică inclusă. +description.ru_RU = "ПуÑтой" набор музыкального оформлениÑ, не Ñодержащий никакой музыки. +description.sk_SK = Sada hudby neobsahujúca hudbu. +description.sl_SI = Glasbeni paket z vkljuÄeno glasbo. +description.sr_RS = Prazan skup muziÄkih numera. +description.sv_SE = Ett musikpaket utan nÃ¥gon musik. +description.ta_IN = இசை இலà¯à®²à®¾à®¤ இசைதà¯à®¤à¯Šà®•à¯à®ªà¯à®ªà¯. +description.th_TH = ชุดเพลงประà¸à¸­à¸šà¹à¸šà¸šà¹„ม่มีเสียงเพลง +description.tr_TR = Müzik içermeyen boÅŸ bir müzik paketi. +description.uk_UA = Порожній набір музики. +description.vi_VN = Gói âm nhạc này không có nhạc nào. +description.zh_CN = 一个没有实际内容的音ä¹åŒ…. +description.zh_TW = ä¸å«ä»»ä½•音樂的音樂集。 + +[files] +theme = +old_0 = +old_1 = +old_2 = +old_3 = +old_4 = +old_5 = +old_6 = +old_7 = +old_8 = +old_9 = +new_0 = +new_1 = +new_2 = +new_3 = +new_4 = +new_5 = +new_6 = +new_7 = +new_8 = +new_9 = +ezy_0 = +ezy_1 = +ezy_2 = +ezy_3 = +ezy_4 = +ezy_5 = +ezy_6 = +ezy_7 = +ezy_8 = +ezy_9 = + +[md5s] + +[names] + +[origin] +default = This file was part of your OpenTTD installation. diff --git a/bin/baseset/no_sound.obs b/bin/baseset/no_sound.obs new file mode 100644 index 0000000..9954845 --- /dev/null +++ b/bin/baseset/no_sound.obs @@ -0,0 +1,67 @@ +; $Id$ +; +; This represents more or less nothingness +; +[metadata] +name = NoSound +shortname = NULL +version = 2 +fallback = true +description = A sound pack without any sounds. +description.af_ZA = 'n Klank stel sonder enige klanke. +description.ar_EG = مجموعة صوت بدوت اصوات Ù…Ø¶Ø§ÙØ© +description.be_BY = "ПуÑты" набор гукавога афармленьнÑ, Ñкі не зьмÑшчае ніÑкіх гукаў. +description.bg_BG = Празен звуков пакет. +description.ca_ES = Un joc de sons sense cap so. +description.cs_CZ = Prázdná sada zvuků. +description.cy_GB = Pecyn sain heb unrhyw effeithiau sain ynddo. +description.da_DK = En lydpakke uden lyde. +description.de_DE = Basissounds ohne Sound. +description.el_GR = Ένα πάκετο ήχων χώÏις ήχους. +description.en_AU = A sound pack without any sounds. +description.en_US = A sound pack without any sounds. +description.es_ES = Un conjunto de sonidos vacío. +description.et_EE = Helikogu ilma helideta. +description.eu_ES = Soinurik gabeko soinu pakete bat +description.fi_FI = Äänipaketti, jossa ei ole ääniä. +description.fr_FR = Un pack de sons sans sons. +description.ga_IE = Pacáiste fuaimeanna gan aon fhuaimeanna ann. +description.gd_GB = Pacaid fhuaimean anns nach eil fuaim sam bith. +description.gl_ES = Un conxunto de sons sen ningún son +description.hr_HR = ZvuÄni paket bez ikakvih zvukova. +description.hu_HU = Hang alapcsomag hangok nélkül. +description.id_ID = Paket efek suara tanpa suara apapun. +description.is_IS = Hljóðpakki án hljóðs. +description.it_IT = Un pacchetto sonoro non contenente alcun suono. +description.ja_JP = 空ã®åŠ¹æžœéŸ³ãƒ‘ãƒƒã‚¯ +description.ko_KR = 아무런 효과ìŒë„ 없는 íš¨ê³¼ìŒ íŒ©ìž…ë‹ˆë‹¤. +description.la_VA = Sarcina sonorum sine ullis sonis. +description.lb_LU = E Soundpack ouni iergendee Sound. +description.lt_LT = Garsų pakas be jokių garsų. +description.nb_NO = En lydpakke uten noen lyder. +description.nl_NL = Een geluidset zonder geluid. +description.nn_NO = Ei lydpakke utan nokon lydar. +description.pl_PL = Zestaw dźwiÄ™ków nie zawierajÄ…cy żadnych dźwiÄ™ków. +description.pt_BR = Um pacote de sons sem sons. +description.pt_PT = Um conjunto de sons vazio. +description.ro_RO = Un set de sunete fără nici un sunet inclus. +description.ru_RU = "ПуÑтой" набор звукового оформлениÑ, не Ñодержащий никаких звуков. +description.sk_SK = Zvuková sada neobsahujúca zvuky. +description.sl_SI = ZvoÄni paket brez zvoka. +description.sr_RS = Prazan skup zvukova. +description.sv_SE = Ett ljudpaket utan nÃ¥gra ljud. +description.ta_IN = ஒலிகள௠இலà¯à®²à®¾à®¤ ஒலி தொகà¯à®ªà¯à®ªà¯. +description.th_TH = ชุดเสียงà¹à¸šà¸šà¹„ร้เสียง +description.tr_TR = Ses içermeyen boÅŸ bir ses kümesi. +description.uk_UA = Порожній набір звуків. +description.vi_VN = Gói âm thanh này không có âm thanh nào. +description.zh_CN = 一个空的音效包. +description.zh_TW = ä¸å«ä»»ä½•音效的音效集。 + +[files] +samples = + +[md5s] + +[origin] +default = This file was part of your OpenTTD installation. diff --git a/bin/baseset/openttd.grf b/bin/baseset/openttd.grf new file mode 100644 index 0000000..efe35ff Binary files /dev/null and b/bin/baseset/openttd.grf differ diff --git a/bin/baseset/opntitle.dat b/bin/baseset/opntitle.dat new file mode 100644 index 0000000..730c176 Binary files /dev/null and b/bin/baseset/opntitle.dat differ diff --git a/bin/baseset/orig_dos.obg b/bin/baseset/orig_dos.obg new file mode 100644 index 0000000..ffe230c --- /dev/null +++ b/bin/baseset/orig_dos.obg @@ -0,0 +1,79 @@ +; $Id$ +; +; This represents the original graphics as on the non-German Transport +; Tycoon Deluxe DOS CD. +; +[metadata] +name = original_dos +shortname = TTDD +version = 1 +palette = DOS +description = Original Transport Tycoon Deluxe DOS edition graphics. +description.af_ZA = Oorspronklike Transport Tycoon Deluxe DOS uitgawe grafieke. +description.ar_EG = النسخة الاصلية من ترانسبورت تايكون ديلوكس الرسومية نسخة الدوس +description.be_BY = ÐÑ€Ñ‹Ò‘Ñ–Ð½Ð°Ð»ÑŒÐ½Ð°Ñ Ò‘Ñ€Ð°Ñ„Ñ–ÐºÐ° з Transport Tycoon Deluxe Ð´Ð»Ñ DOS. +description.bg_BG = Оригинални графики на Transport Tycoon Deluxe за DOS. +description.ca_ES = Gràfics originals de Transport Tycoon Deluxe per a DOS. +description.cs_CZ = Původní sada grafik Transport Tycoon Deluxe (verze pro DOS). +description.cy_GB = Graffeg gwreiddiol fersiwn DOS o Transport Tycoon Deluxe. +description.da_DK = Originalgrafik fra Transport Tycoon Deluxe DOS-version. +description.de_DE = Original Transport Tycoon Deluxe DOS Basisgrafiken. +description.el_GR = ΑÏχικά γÏαφικά από το Transport Tycoon Deluxe έκδοση DOS. +description.en_AU = Original Transport Tycoon Deluxe DOS edition graphics. +description.en_US = Original Transport Tycoon Deluxe DOS edition graphics. +description.es_ES = Gráficos originales de Transport Tycoon Deluxe versión DOS. +description.et_EE = Algse Transport Tycoon Deluxe DOSi versiooni graafika. +description.fi_FI = Alkuperäiset Transport Tycoon Deluxen DOS-version grafiikat. +description.fr_FR = Graphiques originaux de Transport Tycoon Deluxe (version DOS). +description.ga_IE = Grafaicí bunaidhTransport Tycoon Deluxe, eagrán DOS. +description.gd_GB = Grafaigeachd aig an deasachadh DOS tùsail aig Transport Tycoon Deluxe. +description.gl_ES = Graficos da edición orixinal de Transport Tycoon Deluxe para DOS. +description.hr_HR = Originalna grafika za Transport Tycoon Deluxe DOS izdanje. +description.hu_HU = Az eredeti Transport Tycoon Deluxe DOS verziójának grafikája. +description.id_ID = Grafik orisinil Transport Tycoon Deluxe versi DOS. +description.is_IS = Upprunalega grafíkin úr Transport Tycoon Deluxe DOS útgáfunni. +description.it_IT = Grafica originale di Transport Tycoon Deluxe, edizione DOS. +description.ja_JP = Transport Tycoon Deluxe オリジナル版 グラフィック (DOS) +description.ko_KR = ì˜¤ë¦¬ì§€ë„ íŠ¸ëžœìŠ¤í¬íЏ 타ì´ì¿¤ 디럭스 ë„스 ì—ë””ì…˜ì˜ ê·¸ëž˜í”½ìž…ë‹ˆë‹¤. +description.la_VA = Graphica ex editione originale Transport Tycoon Deluxe DOS. +description.lb_LU = Original Transport Tycoon Deluxe DOS Editioun Grafik. +description.lt_LT = Originali Transport Tycoon Deluxe DOS leidimo grafika. +description.nb_NO = Original grafikk fra Transport Tycoon Deluxe for DOS. +description.nl_NL = Originele graphics van de Transport Tycoon Deluxe DOS-versie. +description.nn_NO = Original grafikk frÃ¥ Transport Tycoon Deluxe for DOS. +description.pl_PL = Oryginalna edycja grafik dla Transport Tycoon Deluxe DOS. +description.pt_BR = Gráficos Originais do Transport Tycoon Deluxe, Edição DOS. +description.pt_PT = Gráficos originais da edição DOS de Transport Tycoon Deluxe. +description.ro_RO = Setul grafic original al Transport Tycoon Deluxe pentru DOS. +description.ru_RU = ÐžÑ€Ð¸Ð³Ð¸Ð½Ð°Ð»ÑŒÐ½Ð°Ñ Ð³Ñ€Ð°Ñ„Ð¸ÐºÐ° из Transport Tycoon Deluxe Ð´Ð»Ñ DOS. +description.sk_SK = Pôvodná grafika Transport Tycoon Deluxe (DOS). +description.sl_SI = Originalna grafika Transport Tycoon Deluxe za razliÄico DOS. +description.sr_RS = Originalni skup grafika Transport Tycoon Deluxe DOS izdanja. +description.sv_SE = Originalgrafiken frÃ¥n Transport Tycoon Deluxe, DOS-utgÃ¥van. +description.ta_IN = அசல௠டிரானà¯à®¸à¯à®ƒà®ªà¯‹à®°à¯à®Ÿà¯ டைகூன௠டீலகà¯à®¸à¯ DOS பதிபà¯à®ªà¯ அசைவூடà¯à®Ÿà®™à¯à®•ளà¯. +description.th_TH = à¸à¸£à¸²à¸Ÿà¸Ÿà¸´à¸à¸•้นตำหรับของ Transport Tycoon Deluxe DOS edition +description.tr_TR = Özgün Transport Tycoon Deluxe DOS sürümü grafikleri. +description.uk_UA = Оригінальна графіка з Transport Tycoon Deluxe DOS edition. +description.vi_VN = Äồ há»a gốc từ phiên bản Transport Tycoon Deluxe trên DOS +description.zh_CN = è¿è¾“大亨DOS豪åŽç‰ˆåŽŸç‰ˆå›¾å½¢åŒ…. +description.zh_TW = 原版 Transport Tycoon Deluxe DOS 版的圖形。 + +[files] +base = TRG1.GRF +logos = TRGI.GRF +arctic = TRGC.GRF +tropical = TRGH.GRF +toyland = TRGT.GRF +extra = OPENTTD.GRF + +[md5s] +TRG1.GRF = 9311676280e5b14077a8ee41c1b42192 +TRGI.GRF = da6a6c9dcc451eec88d79211437b76a8 +TRGC.GRF = ed446637e034104c5559b32c18afe78d +TRGH.GRF = ee6616fb0e6ef6b24892c58c93d86fc9 +TRGT.GRF = e30e8a398ae86c03dc534a8ac7dfb3b6 +OPENTTD.GRF = 505d96061556d3bb5cec6234096ec5bc + +[origin] +default = You can find it on your Transport Tycoon Deluxe CD-ROM. +OPENTTD.GRF = This file was part of your OpenTTD installation. diff --git a/bin/baseset/orig_dos.obs b/bin/baseset/orig_dos.obs new file mode 100644 index 0000000..5ae6586 --- /dev/null +++ b/bin/baseset/orig_dos.obs @@ -0,0 +1,67 @@ +; $Id$ +; +; This represents the original sounds as on the Transport +; Tycoon Deluxe DOS CD. +; +[metadata] +name = original_dos +shortname = TTDO +version = 0 +description = Original Transport Tycoon Deluxe DOS edition sounds. +description.af_ZA = Oorspronklike Transport Tycoon Deluxe DOS uitgawe klanke. +description.ar_EG = النسخة الاصلية من ترانسبورت تايكون ديلوكس الصوتية نسخة الدوس +description.be_BY = Ðрыґінальны набор гукавога Ð°Ñ„Ð°Ñ€Ð¼Ð»ÐµÐ½ÑŒÐ½Ñ Ð· гульні Transport Tycoon Deluxe Ð´Ð»Ñ DOS. +description.bg_BG = Оригинални звуци на Transport Tycoon Deluxe за DOS. +description.ca_ES = Sons originals de Transport Tycoon Deluxe per a DOS. +description.cs_CZ = Původní sada zvuků Transport Tycoon Deluxe (verze pro DOS). +description.cy_GB = Effeithiau sain gwreiddiol fersiwn DOS o Transport Tycoon Deluxe. +description.da_DK = Originallyd fra Transport Tycoon Deluxe DOS-version. +description.de_DE = Original Transport Tycoon Deluxe DOS Basissounds. +description.el_GR = ΑÏχικοί ήχοι από το Transport Tycoon Deluxe έκδοση DOS. +description.en_AU = Original Transport Tycoon Deluxe DOS edition sounds. +description.en_US = Original Transport Tycoon Deluxe DOS edition sounds. +description.es_ES = Sonidos originales de Transport Tycoon Deluxe versión DOS. +description.et_EE = Algse Transport Tycoon Deluxe DOSi versiooni helid. +description.fi_FI = Alkuperäiset Transport Tycoon Deluxen DOS-version äänet. +description.fr_FR = Sons originaux de Transport Tycoon Deluxe (version DOS). +description.ga_IE = Fuaimeanna bunaidh Transport Tycoon Deluxe, eagrán DOS. +description.gd_GB = Fuaimean aig an deasachadh DOS tùsail aig Transport Tycoon Deluxe. +description.gl_ES = Sons da edición orixinal de Transport Tycoon Deluxe para DOS. +description.hr_HR = Originalni zvukovi za Transport Tycoon Deluxe DOS izdanje. +description.hu_HU = Az eredeti Transport Tycoon Deluxe DOS verziójának hangjai. +description.id_ID = Efek suara orisinil Transport Tycoon Deluxe versi DOS. +description.is_IS = Upprunalega hljóðið úr Transport Tycoon Deluxe DOS útgáfunni. +description.it_IT = Suoni originali di Transport Tycoon Deluxe, edizione DOS. +description.ja_JP = Transport Tycoon Deluxe オリジナル版 効果音 (DOS) +description.ko_KR = ì˜¤ë¦¬ì§€ë„ íŠ¸ëžœìŠ¤í¬íЏ 타ì´ì¿¤ ë„스 ì—ë””ì…˜ì˜ íš¨ê³¼ìŒìž…니다. +description.la_VA = Soni ex editione originale Transport Tycoon Deluxe DOS. +description.lb_LU = Original Transport Tycoon Deluxe DOS Editioun Sound. +description.lt_LT = OriginalÅ«s Transport Tycoon Deluxe DOS leidimo garsai. +description.nb_NO = Originale lyder fra Transport Tycoon Deluxe for DOS. +description.nl_NL = Originele geluiden van de Transport Tycoon Deluxe DOS-versie. +description.nn_NO = Originale lydar frÃ¥ Transport Tycoon Deluxe for DOS. +description.pl_PL = Oryginalna edycja dźwiÄ™ków dla Transport Tycoon Deluxe DOS. +description.pt_BR = Sons Originais do Transport Tycoon Deluxe, Edição DOS. +description.pt_PT = Sons originais da edição DOS de Transport Tycoon Deluxe. +description.ro_RO = Setul de sunete original al Transport Tycoon Deluxe pentru DOS. +description.ru_RU = Оригинальный набор звукового Ð¾Ñ„Ð¾Ñ€Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¸Ð· игры Transport Tycoon Deluxe Ð´Ð»Ñ DOS. +description.sk_SK = Pôvodné zvuky Transport Tycoon Deluxe (DOS). +description.sl_SI = Originalni zvoki Transport Tycoon Deluxe razliÄice DOS. +description.sr_RS = Originalni skup zvukova Transport Tycoon Deluxe DOS izdanja. +description.sv_SE = Originalljuden frÃ¥n Transport Tycoon Deluxe, DOS-utgÃ¥van. +description.ta_IN = அசல௠டிரானà¯à®¸à¯à®ƒà®ªà¯‹à®°à¯à®Ÿà¯ டைகூன௠டீலகà¯à®¸à¯ DOS பதிபà¯à®ªà¯ ஒலிகளà¯. +description.th_TH = เสียงต้นตำหรับของ Transport Tycoon Deluxe DOS edition +description.tr_TR = Özgün Transport Tycoon Deluxe DOS sürümü sesleri. +description.uk_UA = Оригінальний набір звуків з Transport Tycoon Deluxe DOS edition. +description.vi_VN = Âm thanh gốc từ phiên bản Transport Tycoon Deluxe trên DOS +description.zh_CN = è¿è¾“大亨DOS豪åŽç‰ˆåŽŸç‰ˆéŸ³æ•ˆåŒ…. +description.zh_TW = 原版 Transport Tycoon Deluxe DOS 版的音效。 + +[files] +samples = SAMPLE.CAT + +[md5s] +SAMPLE.CAT = 422ea3dd074d2859bb51639a6e0e85da + +[origin] +default = You can find it on your Transport Tycoon Deluxe CD-ROM. diff --git a/bin/baseset/orig_dos_de.obg b/bin/baseset/orig_dos_de.obg new file mode 100644 index 0000000..5649613 --- /dev/null +++ b/bin/baseset/orig_dos_de.obg @@ -0,0 +1,79 @@ +; $Id$ +; +; This represents the original graphics as on the German Transport +; Tycoon Deluxe DOS CD. It contains one broken sprite. +; +[metadata] +name = original_dos_de +shortname = TTDD +version = 0 +palette = DOS +description = Original Transport Tycoon Deluxe DOS (German) edition graphics. +description.af_ZA = Oorspronklike Transport Tycoon Deluxe DOS (German) uitgawe grafieke. +description.ar_EG = النسخة الاصلية من ترانسبورت تايكون ديلوكس الالمانية نسخة الدوس +description.be_BY = ÐÑ€Ñ‹Ò‘Ñ–Ð½Ð°Ð»ÑŒÐ½Ð°Ñ Ò‘Ñ€Ð°Ñ„Ñ–ÐºÐ° зь нÑмецкай верÑÑ–Ñ– Transport Tycoon Deluxe Ð´Ð»Ñ DOS. +description.bg_BG = Оригинални графики на Transport Tycoon Deluxe за DOS (немÑки) . +description.ca_ES = Gràfics originals de Transport Tycoon Deluxe per a DOS (Alemany). +description.cs_CZ = Původní sada grafik Transport Tycoon Deluxe (nÄ›mecká verze pro DOS). +description.cy_GB = Graffeg gwreiddiol fersiwn DOS (Almaenig) o Transport Tycoon Deluxe. +description.da_DK = Originalgrafik fra Transport Tycoon Deluxe DOS (Tysk) version. +description.de_DE = Original Transport Tycoon Deluxe DOS (Deutsch) Basisgrafiken. +description.el_GR = ΑÏχικά γÏαφικά από το Transport Tycoon Deluxe έκδοση DOS (ΓεÏμανικό). +description.en_AU = Original Transport Tycoon Deluxe DOS (German) edition graphics. +description.en_US = Original Transport Tycoon Deluxe DOS (German) edition graphics. +description.es_ES = Gráficos originales de Transport Tycoon Deluxe versión DOS (Alemán). +description.et_EE = Algse Transport Tycoon Deluxe DOSi (Saksa) versiooni graafika. +description.fi_FI = Alkuperäiset Saksassa julkaistun Transport Tycoon Deluxen DOS-version grafiikat. +description.fr_FR = Graphiques originaux de Transport Tycoon Deluxe (version DOS allemande). +description.ga_IE = Grafaicí bunaidhTransport Tycoon Deluxe, eagrán DOS (Gearmánach). +description.gd_GB = Grafaigeachd aig an deasachadh DOS (Gearmailteach) tùsail aig Transport Tycoon Deluxe. +description.gl_ES = Graficos da edición orixinal (alemá) de Transport Tycoon Deluxe para DOS. +description.hr_HR = Originalna grafika za Transport Tycoon Deluxe DOS (NjemaÄki) izdanje. +description.hu_HU = Az eredeti Transport Tycoon Deluxe DOS (német) verziójának grafikája. +description.id_ID = Grafik orisinil Transport Tycoon Deluxe versi DOS (Jerman). +description.is_IS = Upprunalega grafíkin úr Transport Tycoon Deluxe DOS (þýsku) útgáfunni. +description.it_IT = Grafica originale di Transport Tycoon Deluxe (tedesco), edizione DOS. +description.ja_JP = Transport Tycoon Deluxe オリジナル版 グラフィック (DOS・ドイツ版) +description.ko_KR = ì˜¤ë¦¬ì§€ë„ íŠ¸ëžœìŠ¤í¬íЏ 타ì´ì¿¤ 디럭스 ë„스 ì—디션(ë…ì¼)ì˜ ê·¸ëž˜í”½ìž…ë‹ˆë‹¤. +description.la_VA = Graphica ex editione originale Transport Tycoon Deluxe DOS (Germanica). +description.lb_LU = Original Transport Tycoon Deluxe DOS (Däitsch) Editioun Grafik. +description.lt_LT = Originali Transport Tycoon Deluxe DOS (VokieÄių) leidimo grafika. +description.nb_NO = Original grafikk fra Transport Tycoon Deluxe for DOS (tysk). +description.nl_NL = Originele graphics van de Duitse Transport Tycoon Deluxe DOS-versie. +description.nn_NO = Original grafikk frÃ¥ Transport Tycoon Deluxe for DOS (tysk). +description.pl_PL = Oryginalna edycja grafik dla Transport Tycoon Deluxe DOS (German). +description.pt_BR = Gráficos Originais do Transport Tycoon Deluxe, Edição DOS alemã. +description.pt_PT = Gráficos originais da edição DOS (Alemã) de Transport Tycoon Deluxe. +description.ro_RO = Setul grafic original al Transport Tycoon Deluxe pentru DOS (ediÅ£ia germană). +description.ru_RU = ÐžÑ€Ð¸Ð³Ð¸Ð½Ð°Ð»ÑŒÐ½Ð°Ñ Ð³Ñ€Ð°Ñ„Ð¸ÐºÐ° из немецкой верÑии Transport Tycoon Deluxe Ð´Ð»Ñ DOS. +description.sk_SK = Pôvodná grafika Transport Tycoon Deluxe (DOS) (v jazyku nemÄina). +description.sl_SI = Originalna grafika Transport Tycoon Deluxe za nemÅ¡ko razliÄico DOS. +description.sr_RS = Originalni skup grafika nemaÄkog Transport Tycoon Deluxe DOS izdanja. +description.sv_SE = Originalgrafiken frÃ¥n Transport Tycoon Deluxe, DOS-utgÃ¥van (tyska). +description.ta_IN = அசல௠டிரானà¯à®¸à¯à®ƒà®ªà¯‹à®°à¯à®Ÿà¯ டைகூன௠டீலகà¯à®¸à¯ DOS (செரà¯à®®à®©à¯) பதிபà¯à®ªà¯ அசைவூடà¯à®Ÿà®™à¯à®•ளà¯. +description.th_TH = à¸à¸£à¸²à¸Ÿà¸Ÿà¸´à¸à¸•้นตำหรับของ Transport Tycoon Deluxe DOS (German) edition +description.tr_TR = Özgün Transport Tycoon Deluxe DOS (Almanca) sürümü grafikleri. +description.uk_UA = Оригінальна графіка з Transport Tycoon Deluxe DOS edition (німецького). +description.vi_VN = Äồ há»a gốc từ phiên bản Transport Tycoon Deluxe trên DOS (tiếng Äức) +description.zh_CN = è¿è¾“大亨DOS豪åŽå¾·è¯­ç‰ˆåŽŸç‰ˆå›¾å½¢åŒ…. +description.zh_TW = 原版 Transport Tycoon Deluxe DOS 版 (德國版) 的圖形。 + +[files] +base = TRG1.GRF +logos = TRGI.GRF +arctic = TRGC.GRF +tropical = TRGH.GRF +toyland = TRGT.GRF +extra = OPENTTD.GRF + +[md5s] +TRG1.GRF = 9311676280e5b14077a8ee41c1b42192 +TRGI.GRF = da6a6c9dcc451eec88d79211437b76a8 +TRGC.GRF = ed446637e034104c5559b32c18afe78d +TRGH.GRF = ee6616fb0e6ef6b24892c58c93d86fc9 +TRGT.GRF = fcde1d7e8a74197d72a62695884b909e +OPENTTD.GRF = 505d96061556d3bb5cec6234096ec5bc + +[origin] +default = You can find it on your Transport Tycoon Deluxe CD-ROM. +OPENTTD.GRF = This file was part of your OpenTTD installation. diff --git a/bin/baseset/orig_win.obg b/bin/baseset/orig_win.obg new file mode 100644 index 0000000..f9bd779 --- /dev/null +++ b/bin/baseset/orig_win.obg @@ -0,0 +1,79 @@ +; $Id$ +; +; This represents the original graphics as on the Transport +; Tycoon Deluxe for Windows CD. +; +[metadata] +name = original_windows +shortname = TTDW +version = 0 +palette = Windows +description = Original Transport Tycoon Deluxe Windows edition graphics. +description.af_ZA = Oorspronklike Transport Tycoon Deluxe Windows uitgawe grafieke. +description.ar_EG = النسخة الاصلية من ترانسبورت تايكون ديلوكس الرسومية نسخة وندوز +description.be_BY = ÐÑ€Ñ‹Ò‘Ñ–Ð½Ð°Ð»ÑŒÐ½Ð°Ñ Ò‘Ñ€Ð°Ñ„Ñ–ÐºÐ° з Transport Tycoon Deluxe Ð´Ð»Ñ Windows. +description.bg_BG = Оригинални графики на Transport Tycoon Deluxe за Windows. +description.ca_ES = Gràfics originals de Transport Tycoon Deluxe per a Windows. +description.cs_CZ = Původní sada grafik Transport Tycoon Deluxe (verze pro Windows). +description.cy_GB = Graffeg gwreiddiol fersiwn Windows o Transport Tycoon Deluxe. +description.da_DK = Originalgrafik fra Transport Tycoon Deluxe Windows-version. +description.de_DE = Original Transport Tycoon Deluxe Windows Basisgrafiken. +description.el_GR = ΑÏχικά γÏαφικά από το Transport Tycoon Deluxe έκδοση Windows. +description.en_AU = Original Transport Tycoon Deluxe Windows edition graphics. +description.en_US = Original Transport Tycoon Deluxe Windows edition graphics. +description.es_ES = Gráficos originales de Transport Tycoon Deluxe versión Windows. +description.et_EE = Algse Transport Tycoon Deluxe Windowsi versiooni graafika. +description.fi_FI = Alkuperäiset Transport Tycoon Deluxen Windows-version grafiikat. +description.fr_FR = Graphiques originaux de Transport Tycoon Deluxe (version Windows). +description.ga_IE = Grafaicí bunaidhTransport Tycoon Deluxe, eagrán Windows. +description.gd_GB = Grafaigeachd aig an deasachadh Windows tùsail aig Transport Tycoon Deluxe. +description.gl_ES = Graficos da edición orixinal de Transport Tycoon Deluxe para Windows. +description.hr_HR = Originalna grafika za Transport Tycoon Deluxe Windows izdanje. +description.hu_HU = Az eredeti Transport Tycoon Deluxe Windows verziójának grafikája. +description.id_ID = Grafik orisinil Transport Tycoon Deluxe versi Windows. +description.is_IS = Upprunalega grafíkin úr Transport Tycoon Deluxe Windows útgáfunni. +description.it_IT = Grafica originale di Transport Tycoon Deluxe, edizione Windows. +description.ja_JP = Transport Tycoon Deluxe オリジナル版 グラフィック (Windows) +description.ko_KR = ì˜¤ë¦¬ì§€ë„ íŠ¸ëžœìŠ¤í¬íЏ 타ì´ì¿¤ 디럭스 ìœˆë„ ì—ë””ì…˜ì˜ ê·¸ëž˜í”½ìž…ë‹ˆë‹¤. +description.la_VA = Graphica ex editione originale Transport Tycoon Deluxe Windows. +description.lb_LU = Original Transport Tycoon Deluxe Windows Editioun Grafik. +description.lt_LT = Originali Transport Tycoon Deluxe Windows leidimo grafika. +description.nb_NO = Original grafikk fra Transport Tycoon Deluxe for Windows. +description.nl_NL = Originele graphics van de Transport Tycoon Deluxe Windows-versie. +description.nn_NO = Original grafikk frÃ¥ Transport Tycoon Deluxe for Windows. +description.pl_PL = Oryginalna edycja grafik dla Transport Tycoon Deluxe Windows. +description.pt_BR = Gráficos Originais do Transport Tycoon, Edição Windows. +description.pt_PT = Gráficos originais da edição Windows de Transport Tycoon Deluxe. +description.ro_RO = Setul grafic original al Transport Tycoon Deluxe pentru Windows. +description.ru_RU = ÐžÑ€Ð¸Ð³Ð¸Ð½Ð°Ð»ÑŒÐ½Ð°Ñ Ð³Ñ€Ð°Ñ„Ð¸ÐºÐ° из Transport Tycoon Deluxe Ð´Ð»Ñ Windows. +description.sk_SK = Pôvodná grafika Transport Tycoon Deluxe (Windows). +description.sl_SI = Originalna grafika Transport Tycoon Deluxe za razliÄico oken(windows). +description.sr_RS = Originalni skup grafika Transport Tycoon Deluxe Windows izdanja. +description.sv_SE = Originalgrafiken frÃ¥n Transport Tycoon Deluxe, Windows-utgÃ¥van. +description.ta_IN = அசல௠டிரானà¯à®¸à¯à®ƒà®ªà¯‹à®°à¯à®Ÿà¯ டைகூன௠டீலகà¯à®¸à¯ விணà¯à®Ÿà¯‹à®¸à¯ பதிபà¯à®ªà¯ அசைவூடà¯à®Ÿà®™à¯à®•ளà¯. +description.th_TH = à¸à¸£à¸²à¸Ÿà¸Ÿà¸´à¸à¸•้ำตำหรับของ Transport Tycoon Deluxe Windows edition +description.tr_TR = Özgün Transport Tycoon Deluxe Windows sürümü grafikleri. +description.uk_UA = Оригінальна графіка з Transport Tycoon Deluxe Windows edition. +description.vi_VN = Äồ há»a gốc từ phiên bản Transport Tycoon Deluxe trên Windows +description.zh_CN = è¿è¾“大亨Windows豪åŽç‰ˆåŽŸç‰ˆå›¾å½¢åŒ…. +description.zh_TW = 原版 Transport Tycoon Deluxe Windows 版的圖形。 + +[files] +base = TRG1R.GRF +logos = TRGIR.GRF +arctic = TRGCR.GRF +tropical = TRGHR.GRF +toyland = TRGTR.GRF +extra = OPENTTD.GRF + +[md5s] +TRG1R.GRF = b04ce593d8c5016e07473a743d7d3358 +TRGIR.GRF = 0c2484ff6be49fc63a83be6ab5c38f32 +TRGCR.GRF = 3668f410c761a050b5e7095a2b14879b +TRGHR.GRF = 06bf2b7a31766f048baac2ebe43457b1 +TRGTR.GRF = de53650517fe661ceaa3138c6edb0eb8 +OPENTTD.GRF = 505d96061556d3bb5cec6234096ec5bc + +[origin] +default = You can find it on your Transport Tycoon Deluxe CD-ROM. +OPENTTD.GRF = This file was part of your OpenTTD installation. diff --git a/bin/baseset/orig_win.obm b/bin/baseset/orig_win.obm new file mode 100644 index 0000000..203c041 --- /dev/null +++ b/bin/baseset/orig_win.obm @@ -0,0 +1,143 @@ +; $Id$ +; +; This represents the original music as on the Transport +; Tycoon Deluxe for Windows CD. +; +[metadata] +name = original_windows +shortname = TTDW +version = 1 +description = Original Transport Tycoon Deluxe Windows edition music. +description.af_ZA = Oorspronklike Transport Tycoon Deluxe Windows uitgawe musiek. +description.ar_EG = النسخة الاصلية من ترانسبورت تايكون ديلوكس الموسيقية نسخة وندوز +description.be_BY = Ðрыґінальны набор музычнага Ð°Ñ„Ð°Ñ€Ð¼Ð»ÐµÐ½ÑŒÐ½Ñ Ð· гульні Transport Tycoon Deluxe Ð´Ð»Ñ Windows. +description.bg_BG = Оригинална музика на Transport Tycoon Deluxe за Windows. +description.ca_ES = Música Original de Transport Tycoon Deluxe per a Windows. +description.cs_CZ = Původní hudba Transport Tycoon Deluxe (verze pro Windows). +description.cy_GB = Cerddoriaeth gwreiddiol fersion Windows o Transport Tycoon Deluxe. +description.da_DK = Originalmusik fra Transport Tycoon Deluxe Windows-version. +description.de_DE = Original Transport Tycoon Deluxe Windows Musikset. +description.el_GR = ΑÏχική μουσική από το Transport Tycoon Deluxe έκδοση Windows. +description.en_AU = Original Transport Tycoon Deluxe Windows edition music. +description.en_US = Original Transport Tycoon Deluxe Windows edition music. +description.es_ES = Música original de Transport Tycoon Deluxe versión Windows. +description.et_EE = Algse Transport Tycoon Deluxe Windowsi versiooni muusika. +description.fi_FI = Alkuperäinen Transport Tycoon Deluxen Windows-version musiikki. +description.fr_FR = Musiques originales de Transport Tycoon Deluxe (version Windows). +description.ga_IE = Ceol bunaidh Transport Tycoon Deluxe, eagrán Windows. +description.gd_GB = Ceòl aig an deasachadh Windows tùsail aig Transport Tycoon Deluxe. +description.gl_ES = Música da edición orixinal de Transport Tycoon Deluxe para Windows. +description.hr_HR = Originalna muzika za Transport Tycoon Deluxe Windows izdanje. +description.hu_HU = Az eredeti Transport Tycoon Deluxe Windows verziójának zenéje. +description.id_ID = Musik pengiring orisinil Transport Tycoon Deluxe versi Windows. +description.is_IS = Upprunalega tónlistin úr Transport Tycoon Deluxe Windows útgáfunni. +description.it_IT = Musica originale di Transport Tycoon Deluxe, edizione Windows. +description.ja_JP = Transport Tycoon Deluxe オリジナル版 音楽 (Windows) +description.ko_KR = ì˜¤ë¦¬ì§€ë„ íŠ¸ëžœìŠ¤í¬íЏ 타ì´ì¿¤ 디럭스 ìœˆë„ ì—ë””ì…˜ì˜ ìŒì•…입니다. +description.la_VA = Musica ex editione originale Transport Tycoon Deluxe Windows. +description.lb_LU = Original Transport Tycoon Deluxe Windows Editioun Musik. +description.lt_LT = Originali Transport Tycoon Deluxe Windows leidimo muzika. +description.lv_LV = OriÄ£inÄlÄ Transport Tycoon Deluxe Windows izdevuma mÅ«zika. +description.nb_NO = Original musikk fra Transport Tycoon Deluxe for Windows. +description.nl_NL = Originele muziek van de Transport Tycoon Deluxe Windows-versie. +description.nn_NO = Original musikk frÃ¥ Transport Tycoon Deluxe for Windows. +description.pl_PL = Oryginalna edycja utworów muzycznych w Transport Tycoon Deluxe Windows. +description.pt_BR = Música Original do Transport Tycoon Deluxe, Edição Windows +description.pt_PT = Música original da edição Windows de Transport Tycoon Deluxe. +description.ro_RO = Setul de muzică original al Transport Tycoon Deluxe pentru Windows. +description.ru_RU = Оригинальный набор музыкального Ð¾Ñ„Ð¾Ñ€Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¸Ð· игры Transport Tycoon Deluxe Ð´Ð»Ñ Windows. +description.sk_SK = Pôvodná hudba z Transport Tycoon Deluxe (Windows). +description.sl_SI = Originalna glasba Transport Tycoon Deluxe razliÄice oken(windows). +description.sr_RS = Originalni skup muziÄkih numera Transport Tycoon Deluxe Windows izdanja. +description.sv_SE = Originalmusiken frÃ¥n Transport Tycoon Deluxe, Windows-utgÃ¥van. +description.ta_IN = அசல௠டிரானà¯à®¸à¯à®ƒà®ªà¯‹à®°à¯à®Ÿà¯ டைகூன௠டீலகà¯à®¸à¯ விணà¯à®Ÿà¯‹à®¸à¯ பதிபà¯à®ªà¯ இசை. +description.th_TH = เพลงต้นตำหรับชอง Transport Tycoon Deluxe Windows edition +description.tr_TR = Özgün Transport Tycoon Deluxe Windows sürümü müzikleri. +description.uk_UA = Оригінальна музика з Transport Tycoon Deluxe Windows edition. +description.vi_VN = Nhạc gốc từ phiên bản Transport Tycoon Deluxe trên Windows +description.zh_CN = Transport Tycoon Deluxe(è¿è¾“大亨Windows豪åŽç‰ˆï¼‰çš„原版音ä¹åŒ… +description.zh_TW = 原版 Transport Tycoon Deluxe Windows 版的音樂。 + +[files] +theme = GM_TT00.GM +old_0 = GM_TT02.GM +old_1 = GM_TT06.GM +old_2 = GM_TT03.GM +old_3 = GM_TT12.GM +old_4 = GM_TT08.GM +old_5 = GM_TT13.GM +old_6 = GM_TT14.GM +old_7 = GM_TT10.GM +old_8 = +old_9 = +new_0 = GM_TT04.GM +new_1 = GM_TT01.GM +new_2 = GM_TT05.GM +new_3 = GM_TT15.GM +new_4 = GM_TT11.GM +new_5 = GM_TT16.GM +new_6 = GM_TT09.GM +new_7 = +new_8 = +new_9 = +ezy_0 = GM_TT18.GM +ezy_1 = GM_TT19.GM +ezy_2 = GM_TT21.GM +ezy_3 = GM_TT17.GM +ezy_4 = GM_TT20.GM +ezy_5 = GM_TT07.GM +ezy_6 = +ezy_7 = +ezy_8 = +ezy_9 = + +[md5s] +GM_TT00.GM = 45cfec1b9d8c7a0ad45e755833cbf221 +GM_TT01.GM = ab14ed3392d848abd2a2e90a9d75d121 +GM_TT02.GM = dd4f696e4be5987ce738257b08b50171 +GM_TT03.GM = a1bfde23343df9e4063419bf29c166b8 +GM_TT04.GM = 4e6943aa0c455203d76c79389054747d +GM_TT05.GM = cee281cb85a2e2343552d97640545a47 +GM_TT06.GM = 26d1de5efa8675f94065784e9d539e49 +GM_TT07.GM = 6f2691e17558f552ec4c565e4ab7139c +GM_TT08.GM = a42bf2cb3340a822f1a69646fc7a487d +GM_TT09.GM = eb35761a58a8df3c59ed8929cce13916 +GM_TT10.GM = 42fecd686720a785d20a78590c466a82 +GM_TT11.GM = 50ef1ef02e49d2112786dd45e69dc3ee +GM_TT12.GM = 4ce707a0e0e72419f0681dd9bd95271b +GM_TT13.GM = e765753be29d889ec818f38009103619 +GM_TT14.GM = 270e2d63bd32b95a4d007ce15a6ce45f +GM_TT15.GM = 89e116a1c0c69f1845cc903a9bfbe460 +GM_TT16.GM = f824e2371b3bedfe61aad4b9c62dd6be +GM_TT17.GM = 1b23eebb0796c1ab99cd97fa7082cf7b +GM_TT18.GM = 15650de3bad645d0e88c4f5c7a2df92a +GM_TT19.GM = 7aec079e15bd09588660b85545ac4dfc +GM_TT20.GM = 1509097889dee617aa1e9a1738a5a930 +GM_TT21.GM = a8d0aaad02e1a762d8d54cf81da56bab + +[names] +GM_TT00.GM = Tycoon DELUXE Theme +GM_TT01.GM = Snarl Up +GM_TT02.GM = Easy Driver +GM_TT03.GM = Little Red Diesel +GM_TT04.GM = City Groove +GM_TT05.GM = Aliens Ate My Railway +GM_TT06.GM = Stoke It +GM_TT07.GM = Don't Walk! +GM_TT08.GM = Sawyer's Tune +GM_TT09.GM = Fell Apart On Me +GM_TT10.GM = Can't Get There From Here +GM_TT11.GM = Hard Drivin' +GM_TT12.GM = Road Hog +GM_TT13.GM = Hold That Train! +GM_TT14.GM = Broomer's Oil Rag +GM_TT15.GM = Goss Groove +GM_TT16.GM = Small Town +GM_TT17.GM = Cruise Control +GM_TT18.GM = Stroll On +GM_TT19.GM = Funk Central +GM_TT20.GM = Jammit +GM_TT21.GM = Movin' On + +[origin] +default = You can find it on your Transport Tycoon Deluxe CD-ROM. diff --git a/bin/baseset/orig_win.obs b/bin/baseset/orig_win.obs new file mode 100644 index 0000000..33164e9 --- /dev/null +++ b/bin/baseset/orig_win.obs @@ -0,0 +1,67 @@ +; $Id$ +; +; This represents the original sounds as on the Transport +; Tycoon Deluxe for Windows CD. +; +[metadata] +name = original_windows +shortname = TTDO +version = 0 +description = Original Transport Tycoon Deluxe Windows edition sounds. +description.af_ZA = Oorspronklike Transport Tycoon Deluxe Windows uitgawe klanke. +description.ar_EG = النسخة الاصلية من ترانسبورت تايكون ديلوكس الصوتية نسخة وندوز +description.be_BY = Ðрыґінальны набор гукавога Ð°Ñ„Ð°Ñ€Ð¼Ð»ÐµÐ½ÑŒÐ½Ñ Ð· гульні Transport Tycoon Deluxe Ð´Ð»Ñ Windows. +description.bg_BG = Оригинални звуци на Transport Tycoon Deluxe за Windows. +description.ca_ES = Sons originals de Transport Tycoon Deluxe per a Windows. +description.cs_CZ = Původní sada zvuků Transport Tycoon Deluxe (verze pro Windows). +description.cy_GB = Effeithiau sain gwreiddiol fersiwn Windows o Transport Tycoon Deluxe. +description.da_DK = Originallyd fra Transport Tycoon Deluxe Windows-version. +description.de_DE = Original Transport Tycoon Deluxe Windows Basissounds. +description.el_GR = ΑÏχικοί ήχοι από το Transport Tycoon Deluxe έκδοση Windows. +description.en_AU = Original Transport Tycoon Deluxe Windows edition sounds. +description.en_US = Original Transport Tycoon Deluxe Windows edition sounds. +description.es_ES = Sonidos originales de Transport Tycoon Deluxe versión Windows. +description.et_EE = Algse Transport Tycoon Deluxe Windowsi versiooni helid. +description.fi_FI = Alkuperäiset Transport Tycoon Deluxen Windows-version äänet. +description.fr_FR = Sons originaux de Transport Tycoon Deluxe (version Windows). +description.ga_IE = Fuaimeanna bunaidh Transport Tycoon Deluxe, eagrán Windows. +description.gd_GB = Fuaimean aig an deasachadh Windows tùsail aig Transport Tycoon Deluxe. +description.gl_ES = Sons da edición orixinal de Transport Tycoon Deluxe para Windows. +description.hr_HR = Originalni zvukovi za Transport Tycoon Deluxe Windows izdanje. +description.hu_HU = Az eredeti Transport Tycoon Deluxe Windows verziójának hangjai. +description.id_ID = Efek suara orisinil Transport Tycoon Deluxe versi Windows. +description.is_IS = Upprunalega hljóðið úr Transport Tycoon Deluxe Windows útgáfunni. +description.it_IT = Suoni originali di Transport Tycoon Deluxe, edizione Windows. +description.ja_JP = Transport Tycoon Deluxe オリジナル版 効果音 (Windows) +description.ko_KR = ì˜¤ë¦¬ì§€ë„ íŠ¸ëžœìŠ¤í¬íЏ 타ì´ì¿¤ 디럭스 ìœˆë„ ì—ë””ì…˜ì˜ íš¨ê³¼ìŒìž…니다. +description.la_VA = Soni ex editione originale Transport Tycoon Deluxe Windows. +description.lb_LU = Original Transport Tycoon Deluxe Windows Editioun Sound. +description.lt_LT = OriginalÅ«s Transport Tycoon Deluxe Windows leidimo garsai. +description.nb_NO = Originale lyder fra Transport Tycoon Deluxe for Windows. +description.nl_NL = Originele geluiden van de Transport Tycoon Deluxe Windows-versie. +description.nn_NO = Originale lydar frÃ¥ Transport Tycoon Deluxe for Windows. +description.pl_PL = Oryginalna edycja dźwiÄ™ków dla Transport Tycoon Deluxe Windows. +description.pt_BR = Sons Originais do Transport Tycoon Deluxe, Edição Windows. +description.pt_PT = Sons originais da edição Windows de Transport Tycoon Deluxe. +description.ro_RO = Setul de sunete original al Transport Tycoon Deluxe pentru Windows. +description.ru_RU = Оригинальный набор звукового Ð¾Ñ„Ð¾Ñ€Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¸Ð· игры Transport Tycoon Deluxe Ð´Ð»Ñ Windows. +description.sk_SK = Pôvodné zvuky Transport Tycoon Deluxe (Windows). +description.sl_SI = Originalni zvoki Transport Tycoon Deluxe razliÄice oken(windows). +description.sr_RS = Originalni skup zvukova Transport Tycoon Deluxe Windows izdanja. +description.sv_SE = Originalljuden frÃ¥n Transport Tycoon Deluxe, Windows-utgÃ¥van. +description.ta_IN = அசல௠டிரானà¯à®¸à¯à®ƒà®ªà¯‹à®°à¯à®Ÿà¯ டைகூன௠டீலகà¯à®¸à¯ விணà¯à®Ÿà¯‹à®¸à¯ பதிபà¯à®ªà¯ ஒலிகளà¯. +description.th_TH = เสียงต้นตำหรับของ Transport Tycoon Deluxe Windows edition +description.tr_TR = Özgün Transport Tycoon Deluxe Windows sürümü sesleri. +description.uk_UA = Оригінальний набір звуків з Transport Tycoon Deluxe Windows edition. +description.vi_VN = Âm thanh gốc từ phiên bản Transport Tycoon Deluxe trên Windows +description.zh_CN = Transport Tycoon Deluxe Windows (è¿è¾“大亨Windows豪åŽç‰ˆ)的原版音效包. +description.zh_TW = 原版 Transport Tycoon Deluxe Windows 版的音效。 + +[files] +samples = SAMPLE.CAT + +[md5s] +SAMPLE.CAT = 9212e81e72badd4bbe1eaeae66458e10 + +[origin] +default = You can find it on your Transport Tycoon Deluxe CD-ROM. diff --git a/bin/game/compat_1.2.nut b/bin/game/compat_1.2.nut new file mode 100644 index 0000000..aa5d48c --- /dev/null +++ b/bin/game/compat_1.2.nut @@ -0,0 +1,25 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +GSLog.Info("1.2 API compatibility in effect."); + +GSTown._SetGrowthRate <- GSTown.SetGrowthRate; +GSTown.SetGrowthRate <- function(town_id, days_between_town_growth) +{ + /* Growth rate 0 caused resetting the custom growth rate. While this was undocumented, it was used nevertheless (ofc). */ + if (days_between_town_growth == 0) days_between_town_growth = GSTown.TOWN_GROWTH_NORMAL; + return GSTown._SetGrowthRate(town_id, days_between_town_growth); +} + +/* 1.5 adds a game element reference to the news. */ +GSNews._Create <- GSNews.Create; +GSNews.Create <- function(type, text, company) +{ + return GSNews._Create(type, text, company, GSNews.NR_NONE, 0); +} diff --git a/bin/game/compat_1.3.nut b/bin/game/compat_1.3.nut new file mode 100644 index 0000000..78a0353 --- /dev/null +++ b/bin/game/compat_1.3.nut @@ -0,0 +1,25 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +GSLog.Info("1.3 API compatibility in effect."); + +GSTown._SetGrowthRate <- GSTown.SetGrowthRate; +GSTown.SetGrowthRate <- function(town_id, days_between_town_growth) +{ + /* Growth rate 0 caused resetting the custom growth rate. While this was undocumented, it was used nevertheless (ofc). */ + if (days_between_town_growth == 0) days_between_town_growth = GSTown.TOWN_GROWTH_NORMAL; + return GSTown._SetGrowthRate(town_id, days_between_town_growth); +} + +/* 1.5 adds a game element reference to the news. */ +GSNews._Create <- GSNews.Create; +GSNews.Create <- function(type, text, company) +{ + return GSNews._Create(type, text, company, GSNews.NR_NONE, 0); +} diff --git a/bin/game/compat_1.4.nut b/bin/game/compat_1.4.nut new file mode 100644 index 0000000..a00431e --- /dev/null +++ b/bin/game/compat_1.4.nut @@ -0,0 +1,17 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +GSLog.Info("1.4 API compatibility in effect."); + +/* 1.5 adds a game element reference to the news. */ +GSNews._Create <- GSNews.Create; +GSNews.Create <- function(type, text, company) +{ + return GSNews._Create(type, text, company, GSNews.NR_NONE, 0); +} diff --git a/bin/game/compat_1.5.nut b/bin/game/compat_1.5.nut new file mode 100644 index 0000000..fe985b9 --- /dev/null +++ b/bin/game/compat_1.5.nut @@ -0,0 +1,8 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ diff --git a/bin/scripts/autoexec.scr.example b/bin/scripts/autoexec.scr.example new file mode 100644 index 0000000..af1b66d --- /dev/null +++ b/bin/scripts/autoexec.scr.example @@ -0,0 +1,4 @@ +# send chat messages from the console with +# ] s i love this chat +# +alias s "say %!" \ No newline at end of file diff --git a/bin/scripts/game_start.scr.example b/bin/scripts/game_start.scr.example new file mode 100644 index 0000000..5a36201 --- /dev/null +++ b/bin/scripts/game_start.scr.example @@ -0,0 +1,2 @@ +start_ai MyAI + diff --git a/bin/scripts/on_client.scr.example b/bin/scripts/on_client.scr.example new file mode 100644 index 0000000..5bbd760 --- /dev/null +++ b/bin/scripts/on_client.scr.example @@ -0,0 +1,2 @@ +echo "Setting default network client settings..." +name = "myname" diff --git a/bin/scripts/on_dedicated.scr.example b/bin/scripts/on_dedicated.scr.example new file mode 100644 index 0000000..5465cd7 --- /dev/null +++ b/bin/scripts/on_dedicated.scr.example @@ -0,0 +1,4 @@ +echo "Setting dedicated network server settings..." +# empty the server password +server_pw = "*" +server_name = "My example dedicated gameserver" diff --git a/bin/scripts/on_server.scr.example b/bin/scripts/on_server.scr.example new file mode 100644 index 0000000..cc799d9 --- /dev/null +++ b/bin/scripts/on_server.scr.example @@ -0,0 +1,3 @@ +echo "Setting default network server settings..." +net_sync_freq = 100 +net_frame_freq = 0 diff --git a/bin/scripts/on_server_connect.scr.example b/bin/scripts/on_server_connect.scr.example new file mode 100644 index 0000000..233cf1b --- /dev/null +++ b/bin/scripts/on_server_connect.scr.example @@ -0,0 +1,2 @@ +# Show a MOTD +say "Welcome..." diff --git a/bin/scripts/pre_dedicated.scr.example b/bin/scripts/pre_dedicated.scr.example new file mode 100644 index 0000000..b41ca51 --- /dev/null +++ b/bin/scripts/pre_dedicated.scr.example @@ -0,0 +1,3 @@ +# set default server port, and have the dedicated server listen on all interfaces +server_ip = all +server_port = 3979 diff --git a/bin/scripts/pre_server.scr.example b/bin/scripts/pre_server.scr.example new file mode 100644 index 0000000..c1b6c82 --- /dev/null +++ b/bin/scripts/pre_server.scr.example @@ -0,0 +1,2 @@ +# set the server port to the default value +server_port = 3979 diff --git a/bin/scripts/readme.txt b/bin/scripts/readme.txt new file mode 100644 index 0000000..8f13e74 --- /dev/null +++ b/bin/scripts/readme.txt @@ -0,0 +1,23 @@ +Scripting +--------- + +OpenTTD supports scripts. + +local scripts: + - 'autoexec.scr' is executed on gamestart [all - use this for custom aliases per ex.] + ++network scripts: + should be used to set client optimization settings: + - 'on_client.scr' is executed when you join a server [all clients] + + - 'on_server_connect.scr' is executed on the server when a client has joined (MOTD) + + should be used to set the servers port/ip and/or server optimization settings/patches: + - 'pre_server.scr' is executed before the servers tcp stack is started [in-game only] + - 'pre_dedicated.scr' is executed before the servers tcp stack is started [dedicated only] + + should be used to set the servers name, password and so on: + - 'on_server.scr' is executed after starting a server [dedicated and in-game] + - 'on_dedicated.scr' is additionally executed after starting a server [dedicated only] + +For examples how a script can look, check the .example examples. diff --git a/changelog.txt b/changelog.txt new file mode 100644 index 0000000..c110109 --- /dev/null +++ b/changelog.txt @@ -0,0 +1,5419 @@ +1.5.3 (2015-12-01) +------------------------------------------------------------------------ +(None) + + +1.5.3-RC1 (2015-11-01) +------------------------------------------------------------------------ +- Fix: When selecting a refit cargo for orders, do not check whether the vehicle is in a depot or station, and do not ask whether the vehicle currently allows station-refitting. Also hide the refit cost for orders, it is not predictable (r27428) +- Fix: Use the NewGRF railtype sorting order in the infrastructure window (r27427) +- Fix: Crash when switching to or taking over companies, when an order window of a vehicle of the new company was opened. Now close those windows [FS#5842] (r27425) +- Fix: Towns did not connect roads to existing roads, unless they had only a single roadbit. Otoh, towns also tried to connect to single roadbit tiles such as tunnels and depots, even though they were not connectable in the direction of interest [FS#6374] (r27424) +- Fix: When towns expanded single-bit roadtiles using a grid-layout, they used the layout position of the neighbouring tile (r27423) +- Fix: Aircraft picked the wrong airport entry point, if airports were rotated by 180 degree [FS#6341] (r27422) +- Fix: Consider text and icon sizes when drawing the client list [FS#6265] (r27421) +- Fix: GrowTownAtRoad sometimes returned false, even when a house was built [FS#6362] (r27420) +- Fix: CmdSellRailWagon did not revert all actions properly when no orderlist could be allocated [FS#6369] (r27419) +- Fix: Desync due to incorrect storage of segments with different railtype in the YAPF cache [FS#6329] [FS#6379] (r27418) +- Fix: When a dedicated server was paused with no clients, the master server advertisement interval was slowed, causing deadvertisement of the server [FS#6368] (r27400) +- Fix: [Makefile] Game script directory and compat*.nut were never installed on *nix (r27399) +- Fix: There are two different availability conditions for fdatasync in the manpage. Use them both, since at least on some MinGW versions one is not enough (r27389) +- Fix: win32 sound driver failed to report errors (r27383) +- Fix: Clickareas in settings tree were misaligned when the filter warning was displayed, if the setting height was defined by the icons instead of the font [FS#6358] (r27366) +- Fix: Center settings filter warning also vertically, and also in case of multiple lines (r27365) + + +1.5.2 (2015-09-01) +------------------------------------------------------------------------ +(None) + + +1.5.2-RC1 (2015-08-01) +------------------------------------------------------------------------ +- Change: Auto-complete partial roads when building level-crossings [FS#6283] (r27309) +- Fix: Do not rerandomise the town name when only cost-estimating the founding [FS#6332] (r27341) +- Fix: Make variety distribution not assume that sea level is at height 0.2 / 3 * TGPGetMaxHeight() [FS#6335] (r27331, r27330, r27329, r27328) +- Fix: Remove corner-case optimisation for line drawing, which failed for dashed lines (r27324) +- Fix: Clipping of inclined lines did not account for the 'horizontal width' being bigger than the 'real width' (r27323, r27322) +- Fix: Incorrect owner assignment when adding/removing road/tram to/from bridges [FS#6317] (r27313, r27312) +- Fix: Mark infrastructure window dirty in more cases (r27311) +- Fix: Prevent breaking of tram-reversal points by adding more road pieces [FS#6283] (r27308) +- Fix: Error message window with manager face failed with GUI zoom [FS#6259] (r27307) +- Fix: Account for road-bridges and drive-through-stops in CanFollowRoad [FS#6320] (r27306, r27305) +- Fix: Password window layout with GUI zoom [FS#6321] (r27304, r27303) +- Fix: Speed-only timetables got assigned times in stations [FS#6313] (r27302, r27301) +- Fix: Enforce the company's default service intervals when purchasing another company [FS#6254] (r27282, r27281) +- Fix: Cloning/autoreplace/autorenew did not copy custom service intervals (r27280) + + +1.5.1 (2015-06-01) +------------------------------------------------------------------------ +(None) + + +1.5.1-RC1 (2015-05-08) +------------------------------------------------------------------------ +- Fix: Do not consider road junctions with trivial dead ends as branch points during town growth [FS#6245] (r27260, r27259, r27244) +- Fix: ScriptList::RemoveList failed to remove a list from itself [FS#6287] (r27258) +- Fix: Combined button+dropdown widgets in order and autoreplace GUI had incorrect hitbox when using GUI zoom [FS#6270] (r27255) +- Fix: When building a lock on DC_AUTO-removable water-based objects, the water class was always set to canal [FS#6264] (r27254) +- Fix: When crossing tram tracks with railroads, cost of extra roads was not being counted [FS#6282] (r27253) +- Fix: Invalid infrastructure counting when crossing tram tracks with railroads [FS#6281] (r27252) +- Fix: Broken error message in configure [FS#6286] (r27250) +- Fix: In some cases town growth failure was considered as success [FS#6240] (r27249, r27247) +- Fix: Town labels on smallmap and zoomed-out viewports were not centered [FS#6257] (r27248) +- Fix: Removing a rail waypoint used the remove-rail-station cost [FS#6251] (r27245) +- Fix: Duplicate frees due to pool item classes not having copy constructors [FS#6285] (r27243) +- Fix: Crash when no AIs were installed due to improper handling of non-ASCII characters by the string pointer lexer [FS#6272] (r27233) +- Fix: Compilation on DragonflyBSD [FS#6274] (r27224, r27223) +- Fix: Use the current maximum speed as limited by bridges, orders etc. for all vehicle types alike when considering increased smoke emissions of vehicles [FS#6278] (r27222) +- Fix: Multi-value keys in the desktop entry shall end with a trailing separator (r27221) +- Fix: Draw path reservation on the whole bridge, not only on the bridge heads (r27209) +- Fix: Draw correct overlay sprites for path reservations on bridges and tunnels (r27208) + + +1.5.0 (2015-04-01) +------------------------------------------------------------------------ +- Fix: [NewGRF] Add Misc. GRF Feature Flag 6 to enable the second rocky tile set [FS#6260] (r27200) + + +1.5.0-RC1 (2015-03-18) +------------------------------------------------------------------------ +- Feature: [NewGRF] Display relative offset changes in the sprite aligner [FS#6236] (r27174) +- Fix: Original road vehicle acceleration crashed for vehicles taking over [FS#6255] (r27190) +- Fix: GCC 5 compilation (r27185, r27183) +- Fix: Data race due to lazy initialisation of objects [FS#5969] (r27178) +- Fix: Compilation with MinGW64 (r27176) +- Fix: Use the regular clipping functions in the sprite aligner instead of some magic [FS#6237] (r27173) +- Fix: Windows randomly drops SetCursorPos calls, breaking the RMB-scrolling [FS#6238] (r27172) + + +1.5.0-beta2 (2015-02-24) +------------------------------------------------------------------------ +- Feature: [NoGo] Game scripts can point to a location, station, industry, or town when publishing news (r27164) +- Feature: Allow changing max heightlevel in scenario editor (r27151) +- Feature: Make use of both rocky tile sets from the base graphics (r27117) +- Change: Scale (non-custom) default window sizes according to GUI zoom (r27147) +- Change: Make statusbar and chat-entry window use the same width as the toolbar (r27146) +- Change: The chatbox-width setting now uses percent of screen width instead of pixels (r27144) +- Change: [NewGRF] Interpret negative positions in industry layouts depending on GRF version (r27138) +- Fix: [SDL, Windows] Right-mouse-button scrolling scrolled/jumped too far, when OpenTTD lagged during mouse event processing (r27167) +- Fix: Toolbars were not invalidated when changing max-vehicles settings [FS#6204] (r27163) +- Fix: Tile selection was drawn outside of map in some cases [FS#6208] (r27162) +- Fix: Reimplement the viewport drawing algorithm [FS#6156] [FS#6206] (r27161) +- Fix: Issues with smallmap and viewport coordinates and transformations (r27160, r27159, r27158) +- Fix: Mark bridge middle tiles dirty when building/removing/changing bridges (r27157) +- Fix: Rounding and unit-conversion inconsistencies in calls to MarkAllViewportsDirty (r27148) +- Fix: Oilrig empty-tile checks were incorrect due to wrong TileIndexDiff->TileIndexDiffC conversion (r27137) +- Fix: Misalignment in generate world window in case of small fonts (r27135) +- Fix: Dragging of free wagons in depot failed with GUI zoom (r27133) +- Fix: Reduce memory footprint of map array by shuffling its members [FS#6218] (r27132, r27126) +- Fix: Dropdown- and tooltip-windows should not steal the focus (r27131) +- Fix: [NewGRF] Action 7/9 condition 0A failed for present, but disabled, NewGRF (r27119) +- Fix: Road vehicles could not reverse to be sent to depots when the following tile has the right type to run on, but could not be entered [FS#6183] (r27107) +- Fix: Use the actual max speed of the vehicle in front when determining if a RV can overtake [FS#6176] (r27106) +- Fix: grow_counter was not properly bounded by growth_rate, but by some other value used to calculate growth_rate [FS#6195] (r27105) +- Fix: [Script] Support 64 bits integers in ScriptLists [FS#6194] (r27104) +- Fix: [Script] Money values would end up wrong in strings when outside the bounds of a 32 bits integer [FS#6194] (r27102) + + +1.5.0-beta1 (2014-12-24) +------------------------------------------------------------------------ +- Feature: Support .txt.gz and -txt.xz changelog, readme and license files in basesets, NewGRFs, etc (r27035, r27034) +- Feature: More height levels [FS#4126] (r27010) +- Feature: Latin translation (r26993) +- Feature: Add option to choose normal, double or quad-size interface (r26990) +- Feature: [Script] Swap method for script lists (r26894) +- Feature: [Script] ScriptStationList_Cargo for sorting cargo by from and via (r26893) +- Feature: [Script] API for retrieving planned flow (r26892) +- Feature: [CargoDist] Predict links for station-autorefitting vehicles (r26889) +- Feature: Setting for limiting the height of bridges (r26882) +- Feature: Make aircraft ascend/descend when they are too close to the ground or too far away (r26866) +- Feature: Allow hiding of non-interesting engines in the GUI (r26805, r26804) +- Feature: Vehicle sorting in autoreplace GUI [FS#1640] (r26800) +- Feature: [NewGRF] Advanced visual effects with multiple effect sprites independent of spawning model (r26988, r26747) +- Feature: Warn about missing industries after generating a map (r26729) +- Feature: Upgrade currently active NewGRFs to newest installed version (r26613) +- Feature: Save and load grfid and md5sum of NewGRFs in config file (r26611) +- Feature: Select an editable preset name for saving (r26610) +- Feature: Cancel cargo delivery from industries/houses to stations after about 21 months of not having picked up any of the cargo (r26582) +- Feature: Give a warning when a plane's orders tell it to use a runway which is too short for it [FS#6009] (r26566) +- Feature: [Script] Extended API for CargoDist (r26557) +- Feature: Show measured order times in timetable GUI also when not timetabled (r26550) +- Feature: Prompt for confirmation when deleting a vehicle group (r26455) +- Feature: Hierarchical vehicle subgroups (r26450) +- Feature: Allow more sound sleep for dedicated servers when there's nothing to do and nobody paying attention (r26449) +- Feature: [NewGRF] Add vehicle modflag 1 (unloading in progress) (r26430) +- Change: Improvements to the man page (r27091, r27012) +- Change: Allow to set the granularity of the tooltip hover time in milliseconds instead of seconds. New default value is 250ms (r26815) +- Change: Follow SI recommendation about spaces between numbers and units [FS#6086] (r26733) +- Change: [CargoDist] Save locations instead of distances in link graphs to reduce size (r26646) +- Change: [Squirrel] Make the internal integer for scripts always 64 bits, so scripts behave the same on 32 and 64 bit architectures and money can be represented properly (r26585, r26584) +- Change: Reshuffle advanced settings tree (r26614, r26536) +- Change: Add backend-independent config-file setting to disable 8bpp video modes, and disable 8bpp by default (r26522) +- Fix: [OS/2] Compile again [FS#6186] (r27092) +- Fix: Compilation with freetype2 version 2.5.4 and newer [FS#6185] (r27079) +- Fix: Variable 47 used the carge translation table of the wrong GRF in case of callback 1D [FS#6182] (r27075) +- Fix: Some lists did not use natural string sorting [FS#6172] (r27063) +- Fix: Mercurial version detection failed if personal presets were configured (r27059) +- Fix: [OSX] Don't require double-press from non-dead console hotkeys [FS#5812] (r27046) +- Fix: Crash when having the vehicle list opened from a buoy or oil rig when the buoy/oil rig is removed (r27030) +- Fix: Unit number was not always fully shown in depots [FS#6102] (r27014) +- Fix: [CargoDist] Reserve cargo only after unloading finished or if the vehicle has the desired cargo already [FS#6110] (r26918) +- Fix: [Squirrel] Loading a value saved as boolean caused it to be of type integer instead of boolean (r26785) +- Fix: [Squirrel] Harden string handling (r26777) +- Fix: [OSX] Implement more of the text editing API to prevent crashes and improve IME support [FS#5972] (r26758) +- Fix: Incorrect saving of order backups [FS#6066] (r26700) +- Fix: Ordering a vehicle to a competitor's rail waypoint displayed an error message. Ignore the click as is done for the other order types to competitor's stuff [FS#6059] (r26692) +- Fix: [Script] Loading/parsing of info .nuts was done in the same VM, causing e.g. constants to break the loading of info of other scripts [FS#5973] (r26617) +- Fix: [CargoDist] Improve estimation of link capacitites (r26549) +- Remove: A bunch of archaic settings from the GUI (r26528, r26526, r26525) + + +1.4.4 (2014-10-21) +------------------------------------------------------------------------ +(None) + + +1.4.4-RC1 (2014-10-08) +------------------------------------------------------------------------ +- Fix: Image widgets stored 32bit SpriteID in uint16 (r26971) +- Fix: Owner of road depot road types were not properly changed upon bankruptcy [FS#6126] (r26955) +- Fix: Compilation on HAIKU (r26922) +- Fix: Crash when enabling 'Full animation' if multiplayer chat text is on screen [FS#6096] (r26919) +- Fix: Height computation of game script text in town GUI did not consider margins [FS#6119] (r26859) +- Fix: [Squirrel] Debian lintian issues (r26853) +- Fix: Compilation of strgen on various platforms like Solaris (r26850) +- Fix: Better display of refit information for articulated vehicles [FS#6113] (r26849, r26848) +- Fix: Do not assign a next hop when returning cargo [FS#6110] (r26847) +- Fix: The ok-button in the OSK for the signs list should just close the OSK [FS#6116] (r26827) + + +1.4.3 (2014-09-23) +------------------------------------------------------------------------ +(None) + + +1.4.3-RC2 (2014-09-14) +------------------------------------------------------------------------ +- Fix: Crashes on joining a server with pending order backups [FS#6112] (r26819) +- Fix: Crashes on start due to dereferencing the -1 index of the file names array of music files (r26809) + + +1.4.3-RC1 (2014-09-07) +------------------------------------------------------------------------ +- Fix: TC_NO_SHADE did not work for 32bpp text rendering (r26792) +- Fix: Loading a game with order backups leaked Orders and left unreachable items in the pool (r26787) +- Fix: Buffer overrun in SQCompiler::Error (r26764) +- Fix: Desync due to not always properly restoring game state from the savegame (r26753) +- Fix: [Script] Crashes and infinite loops when using lists in item-descending order [FS#6085] (r26744) +- Fix: Incorrect CFLAGS when enabling gprof profiling (r26737, r26735) +- Fix: Do not reset the last selected airport or layout, unless it is really necessary [FS#6083] (r26732) +- Fix: Use the normal search path to look for xdg-open at Unix [FS#6077] (r26724) +- Fix: Properly check for cargo acceptance of houses [FS#5997] (r26723) + + +1.4.2 (2014-08-16) +------------------------------------------------------------------------ +(None) + + +1.4.2-RC2 (2014-08-03) +------------------------------------------------------------------------ +- Change: Use awk instead of trying to convince cpp to preprocess nfo files (r26708) +- Fix: CMD_CLEAR_ORDER_BACKUP should not be suppressed by pause modes (r26716) +- Fix: [NewGRF] Parameters to SCC_NEWGRF_PUSH_WORD and SCC_NEWGRF_UNPRINT were not skipped during drawing (r26713) +- Fix: [OSX] Compilation fails with some lzo2 versions, if __LP64__ is defined to 0 instead of checking whether it is defined [FS#6069] (r26709) +- Fix: Wrong breakdown sound was played for ships [FS#6015] (r26706) +- Fix: Integer overflows in acceleration code causing either too low acceleration or too high acceleration [FS#6067] (r26702) +- Fix: Discard incorrectly saved order backups when clients join [FS#6066] (r26700) +- Fix: Do not crash when trying to show an error about vehicle in a NewGRF and the NewGRF was not loaded at all (r26699) +- Fix: Slovak uses space as group separator in numbers [FS#6064] (r26695) +- Fix: Tighten parameter bound checks on GSCargoMonitor functions, and return -1 on out-of-bound parameters (r26685) + + +1.4.2-RC1 (2014-07-03) +------------------------------------------------------------------------ +- Fix: CargoPacket::SourceStation() returns a StationID (r26660) +- Fix: Days in dates are not represented by ordinal numbers in all languages [FS#6047] (r26657) +- Fix: Production cheat cannot be allowed to be active in multiplayer for desync reasons, even when activated in singleplayer previously [FS#6044] (r26656) +- Fix: Make sure an 'abs' is used that supports int64 when using 'abs' on those variables (r26651) +- Fix: Support save/load chunk lengths of up to (1 << 32) - 1 [FS#6041] (r26650) +- Fix: Incorrect usage of string commands in the base language [FS#6037] (r26642, r26640, r26639, r26632) +- Fix: Segmentation fault when encountering a .obg/.obs/.obm with empty string/zero length MD5 checksums [FS#6038] (r26637) +- Fix: The 'Load' button was not properly enabled/disabled for old savegames without NewGRF information (r26634) +- Fix: If the video driver fails to supply a list of resolutions, display an error message [FS#6012] (r26629) + + +1.4.1 (2014-06-02) +------------------------------------------------------------------------ +- Fix: First send packages about new company, then clients joining it to admin port [FS#6025] (r26616) + + +1.4.1-RC2 (2014-05-18) +------------------------------------------------------------------------ +- Fix: Save/load issues on big endian machines (r26593, r26590, r26589) +- Fix: Consider multiheaded trains in station refits [FS#5995] (r26586) +- Fix: Game script could be changed in game by double clicking [FS#5974] (r26583) +- Fix: Transfer stations also should have a cargo rating [FS#5989] (r26581, r26580) +- Fix: [Network] AIs would not reset certain network state information upon creation of their company [FS#6003] (r26578, r26576) +- Fix: [Network] Client of non-dedicated server was not correctly put into the first company for all state variables [FS#6001] (r26577) + + +1.4.1-RC1 (2014-05-04) +------------------------------------------------------------------------ +- Change: Remove demand calculation based on tiles (r26484) +- Change: Use pkg-config for libpng as well (r26435, r26433, r26432) +- Change: Use better distance metric for link graph [FS#5941] (r26411) +- Fix: [Windows] Crash when the operating system performs the "paint" callback during window creation [FS#5994] (r26539, r26538) +- Fix: OpenBSD compilation [FS#5992] (r26523) +- Fix: prevent from ever reading huge (or negative) amounts of data in strgen (r26521) +- Fix: Severity rating of dedicated server messages during world generation (r26518) +- Fix: Buffer overruns in handling of symbolic links inside tars (r26514) +- Fix: Incorrect usage of strecpy (r26505, r26485) +- Fix: Reading console input on dedicated server relied on unspecified behaviour (r26496) +- Fix: Allow single-vehicle consists to station-refit in a meaningful way (r26483) +- Fix: Prevent comparing to NULL when strndup could not allocate memory (r26476) +- Fix: Potentially undefined shifts in NewGRF code (r26475) +- Fix: Make sure there is no uninitialised sprite data (r26473) +- Fix: Draw text shadow for ellipses (r26467) +- Fix: Add special handling for PALETTE_CRASH to work for non-8bpp-mapped sprites (r26463) +- Fix: Avoid division by 0 when scaling flow values [FS#5970] (r26448) +- Fix: Draw links to match _settings_game.vehicle.road_side [FS#5961] (r26445) +- Fix: Load button for heightmap list was missing [FS#5953] (r26428) +- Fix: Do not crash when supplying an invalid filename without extension to cmd parameter -q (r26423) +- Fix: Some road constructions used the rail sound effect [FS#5946] (r26422) +- Fix: Goal GUI failed to shade [FS#5948] (r26420) +- Fix: Shares button state was not appropriately updated when switching setting or company [FS#5947] (r26416) + + +1.4.0 (2014-04-01) +------------------------------------------------------------------------ +(None) + + +1.4.0-RC1 (2014-03-18) +------------------------------------------------------------------------ +- Feature: [Script] APIs to get cargo waiting from/via other station (r26396) +- Fix: Do not explain "symmetric" cargodist mode when the setting does not allow it [FS#5939] (r26394) +- Fix: Update distances between link graph nodes when station sign is moved (r26393) +- Fix: No need to call OnFocus twice [FS#5933] (r26392) +- Fix: Select a specific font size when freetype fails to select one automatically [FS#5885] (r26389) +- Fix: Return correct values from ICU iterators in case of leading or trailing whitespace [FS#5924] (r26384) +- Fix: All goal commands invalidated the goal list of company 0 [FS#5932] (r26382) + + +1.4.0-beta5 (2014-02-25) +------------------------------------------------------------------------ +- Feature: Warn the user about empty setting search results, and about missing setting search results due to filtering (r26322, r26321) +- Feature: [NewGRF] Extend object variable 0x60 to also return the view [FS#5696] (r26316) +- Feature: Allow map sizes up to 4096x4096 (r26319) +- Feature: [NoGo] Allow GS to hide story page date (r26307) +- Feature: [NoGo] More story APIs: RemovePageElement, GetCompany, GetDate, SetDate (r26306) +- Feature: [NoGo] ScriptStoryPageElementList() - a list of all story page elements for a given page (r26305) +- Feature: [NoGo] ScriptStoryPageList() - a list of all story pages (r26303) +- Change: improve the performance of map generation (r26313, r26312, r26311, r26310, r26309, r26308) +- Fix: Station sizes > 8 were always allowed [FS#5929] (r26375) +- Fix: [NewGRF] Mixed up callback mask flags in station inspect window [FS#5928] (r26374) +- Fix: Calling DoCommandP during the gameloop cleared pending persistent storage changes [FS#5831] (r26371) +- Fix: [Windows] Use a separate event to indicate that the drawing thread has finished initialising, preventing potential deadlocks (r26367) +- Fix: [Windows] Protect the whole video driver from concurrent access (r26366) +- Fix: [Windows] Do not draw the cursor when its sprite is not ready and set _screen.dst_ptr immediately when the buffer changes [FS#5867] (r26365) +- Fix: Writing out of the bounds of the rail type map [FS#5892] (r26364) +- Fix: Reset the default window size icon size just like all the other cached icon sizes [FS#5906] (r26362) +- Fix: ClientSizeChanged is only called via WndProcGdi which already has the mutex [FS#5922] (r26360) +- Fix: Some order options do not combine with others, e.g. go via + full load [FS#5845] (r26357) +- Fix: Protect all VideoDriver_SDL methods with the (now recursive) _draw_mutex (r26351) +- Fix: Make sure link graph jobs can delete themselves after SLA_NULL [FS#5898] (r26347) +- Fix: Call Layouter::ReduceLineCache from GenerateTownName in all cases to keep cache size in check [FS#5870] (r26346) +- Fix: Rewrite SmallStack so that it does not use a pool and is re-entrant (r26343) +- Fix: Reroute cargo when automatic distribution is switched off [FS#5902] (r26341) +- Fix: Do not redraw the link graph overlay if it is empty [FS#5908] (r26338) +- Fix: Some inconsistencies regarding link graph (job) IDs (r26331) +- Fix: The case of rerouting cargo from one VehicleCargoList to another (r26330) +- Fix: Take care of next_station when reassigning from MTA_DELIVER to MTA_TRANSFER [FS#5901] (r26327) +- Fix: when autosaving the message about a save already happening could be shown, even though the code's intention was to not show it [FS#5871] (r26326) +- Fix: Check whether NewGRF change vehicle capacity when they are not supposed to, and truncate cargo appropriately if they are allowed to [FS#5897] (r26317) +- Fix: The giant-screenshot confirmation window only triggered for ridiculously big screenshots, not for ludicrously big ones [FS#5899] (r26314) + + +1.4.0-beta4 (2014-02-06) +------------------------------------------------------------------------ +- Change: [NewGRF] Make vehicle variable 61 return 'not available' instead of zero when using it in invalid callback contexts (r26294) +- Feature: Display speed limit also for road bridges in the TileInfo window [FS#5849] (r26277) +- Fix: [NoGo] Invalid DoCommand return callback for method returning bool (r26298) +- Fix: Correctly identify opposite ends of bridges and tunnels when converting rails [FS#5866, FS#5888] (r26291) +- Fix: Prevent infinite recursion also in RefreshLinks [FS#5878] (r26283) +- Fix: [NoAI] Some RemoveRail methods required to set a valid railtype, though it was not used anyway. Remove the need to set one [FS#5853] (r26279) +- Fix: Do not spawn link graph jobs for link graphs with only one node [FS#5874] (r26276) +- Fix: [NewGRF] If NewGRF provided the same station name for different industry types, stations would end up with same name. So also consider the provided name, not only the industry type (r26275) + + +1.4.0-beta3 (2014-01-21) +------------------------------------------------------------------------ +- Feature: Several small performance improvements with the SSE blitters (r26260, r26259, r26256, r26255, r26254) +- Feature: [NewGRF] Add StringCodes 9A 1B, 9A 1C and 9A 1D to display amounts of cargo (r26244) +- Fix: Do not run into infinite recursion when getting next stopping station [FS#5865] (r26267, r26263) +- Fix: Update smallmap overlay if player joins different company and make sure company masks are valid [FS#5860] (r26266) +- Fix: Do not rebuild the link graph overlay cache twice in a row (r26265) +- Fix: Custom currency was reset on game start (r26262) +- Fix: Possible out of bounds reads with the SSE blitters [FS#5854, FS#5855] (r26247) +- Fix: Do not over reserve after autorefit, but do reserve mail for aircraft (r26236) +- Fix: Decimal and digit separators were swapped for Korean language (r26235) + + +1.4.0-beta2 (2014-01-07) +------------------------------------------------------------------------ +- Feature: Blitter autoselection is now based on full animation state, so a non-animated specialised blitter will generally be chosen when animation is turned off (r26217) +- Feature: Specialised animated SSE4 blitter, and non-animated SSE4.1, SSSE3 and SSE2 blitters, improving the blitting significantly in many situations (r26214, r26213, r26212, r26211) +- Feature: Specialised SSE 4.1 sprite sorter, improving the sorting performance significantly (r26205) +- Fix: Validate everything from ini, obg, obs, obs, ... files [FS#5829] (r26206) +- Fix: Allow refitting at station if cargo has already been reserved (r26187) +- Fix: Visual effects did not work for articulated RV parts (r26180) + + +1.4.0-beta1 (2013-12-24) +------------------------------------------------------------------------ +- Feature: [NewGRF] Vehicle variable 4D for determining the position within an articulated vehicle (r26157) +- Feature: [NewGRF] Invalidate vehicle colour palette when leaving a station [FS#5669] (r26027) +- Feature: [NoGo] New goal type that show a story page when clicked (r26012) +- Feature: Optional filter parameter to the 'content state' console command, to limit the content list to only content where the name match the filter (r26000) +- Feature: When calling the 'content select' console command without args, display all selected content (r25999) +- Feature: XDG base directory support [FS#5385] (r25975) +- Feature: [Script] ScriptTown::GetFundBuildingsDuration (r25969) +- Feature: [Script] ScriptTown::TOWN_GROWTH_NONE to indicate no town growth via ScriptTown::SetGrowthRate and GetGrowthRate (r25968) +- Feature: [NoGo] GSTown::TOWN_GROWTH_NORMAL to reset a town growth rate set previously via GSTown::SetGrowthRate (r25967) +- Feature: [NewGRF Debugging] Inspecting other vehicles in a chain (r25946) +- Feature: [NewGRF] Object property 0x18 to allow specifying the number of objects of that type being placed upon map creation (r25878) +- Feature: [NewGRF] Object property 0x10, bit 13 indicating that object amount scales with water content of map border (e.g. used for lighthouses) (r25874) +- Feature: Highlight active goto item in order list dropdown [FS#5784] (r25859) +- Feature: [Admin] Send info on bankruptcy quarters also in ADMIN_PACKET_SERVER_COMPANY_INFO [FS#5756] (r25845) +- Feature: Increase maximum number of object instances on the map from 64k to about 16M (r25844) +- Feature: Increase the total number of object types from 256 to 64000 (r25835) +- Feature: [NewGRF] Increase the object class limit from 32 to 255 (r25831) +- Feature: Toggle button for wrapping lines in the textfile GUI [FS#5748] (r25816) +- Feature: [NoGo] Game Scripts can now charge fees and give money to companies (r25788) +- Feature: [Script] Allow AIs and GS to found towns. Allow GS to rename towns (r25785) +- Feature: Add keywords to the openttd.desktop.in file (r25783) +- Feature: Sticky and shade buttons for jukebox window [FS#5743] (r25776) +- Feature: Additional layered main toolbar arrangements (r25772) +- Feature: Allow implicit orders even if no explicit ones are given (r25735) +- Feature: [OSX] Pinch gesture support for zooming [FS#4760] (r25666) +- Feature: Split unit localisation choice into a choice per type of unit, and move it to the advanced settings (r25508) +- Feature: Have tractive effort in imperial (lbf) and metric (kgf) units, have weights and volumes in imperial units (short tons, gallons) [FS#5482] (r25508) +- Feature: Differentiate between total waiting cargo count and available (not reserved) cargo count in the station list and sort based on the cargo count, not the cargo value (r25405) +- Feature: Timetable spreading of vehicles by Ctrl+Click when setting a start date (r25377) +- Feature: Allow opening a goal list and story window specific to a company (r25372, r25369) +- Feature: Show cargo by next hops and final destinations in the station GUI (r25365) +- Feature: Consider cargo waiting at other stations for rating at the origin station (r25362) +- Feature: Distribute cargo according to plan given by linkgraph (r25361) +- Feature: [NoGo] GUI for viewing story pages (r25344) +- Feature: Add industry list to scenario editor's map menu (r25335) +- Feature: [NoGo] Allow more concurrent goals in a game (r25299) +- Feature: [NoGo] Goals can now have a progress text and/or be marked as completed (r25296) +- Feature: Allow saving window sizes as default sizes (r25295) +- Feature: Add another button to window title bars to resize the window to its default size (r25294) +- Feature: Save stickyness of windows when Ctrl+Clicking the sticky button (r25292) +- Feature: When opening the object-build window, restore the object build-window to the previous state (r25284) +- Feature: Show the approximate monthly supply to a station of the different cargoes (r25272) +- Feature: [Win32] Driver param for the DirectMusic driver to specify the output port to use [FS#5552] (r25269) +- Feature: Linkgraph overlay over main viewport (r25264) +- Feature: Linkgraph overlay for smallmap (r25262) +- Feature: Display imminent closure of an industry in its view window (r25238) +- Feature: [NewGRF] Expose sprite base of foundation and shore sprites via Action D Game Variables (r25230) +- Feature: [NewGRF] Variable 0x82 for canals and rivers (dike map) (r25229) +- Feature: [Script] ScriptStation::HasRating [FS#5514] (r25150) +- Feature: Add sorting on rating for the town directory window [FS#5288] (r25097) +- Feature: Introduce dropdown for selecting the sort criterion in the town directory window (r25094) +- Feature: Georgian Lari and Iranian Rial as currencies [FS#5212] (r25076) +- Feature: Collapse subtypes in the refit GUI and only expand them after selecting the cargo type (r25044) +- Feature: Only display subtypes in the refit GUI which are available for all selected vehicles. Also add a generic list item to refit while keeping the subtypes of individual vehicles [FS#3764] (r25043) +- Feature: Show the amount of cargo that has already been reserved by full loading vehicles in the station (r25013) +- Change: [NewGRF] Reset the temporary storage registers for every sprite resolving (r26173) +- Change: Improve layout of build-airport GUI [FS#5832] (r26165) +- Change: Make it slightly more clear what ports are coming from where in the debug output when listening (r25997) +- Change: Preselect the current replacement in the right-side list of the autoreplace GUI, instead of selecting the first resp. previous item [FS#5734] (r25919) +- Change: Unify behaviour when clicking on different items in the goto dropdown list when giving orders (r25894) +- Change: Do not offer subsidies for auto-distributed cargo [FS#5766] (r25882) +- Change: Allow to remove unowned objects unless they have the 'unremovable' flag (r25879) +- Change: In scenario editor allow to build all objects which were available at any point in the past to support building scenarios with historic items (r25875) +- Change: Display the cost to upgrade a bridge at the end of bridge that was clicked and not the other end, which could be outside of the screen in some cases (r25854) +- Change: [NewGRF] Lower the limit of airport tile types, house types, industry tile types and object types per NewGRF from 256 to 255 to prevent usage of ID 0xFF in Action3, and thus allowing it to become an extended byte somewhen (r25841, r25839, r25837, r25834) +- Change: Clarify the relevance of the permissible palettes (r25792) +- Change: [NewGRF] Invalidate vehicle recolour palette during (un)loading [FS#5669] (r25648) +- Change: If an editbox is configured to be cleared with ESC, but the editbox is already empty, unselect the editbox instead (r25647) +- Change: Make the bridge and object picker not restore their previous size, but the previously saved size (r25543) +- Change: Right align the infrastructure statistics [FS#5595] (r25515) +- Change: Clarify the meaning of the server advertisement settings (r25252) +- Fix: Unify the time a RV needs to travel through a curve [FS#5831] (r26169) +- Fix: Certain hotkeys crashed the content GUI when the list was empty [FS#5834] (r26167) +- Fix: Backup data of altered persistent storage arrays was freed twice [FS#5830] (r26161) +- Fix: [Script] Various API functions did not check whether ScriptRoad::SetCurrentRoadType was called appropriately [FS#5825] (r26149) +- Fix: [Script] API failed for vehicles with only implicit orders [FS#5824] (r26148) +- Fix: Several fixes found by static code analysis (r26132, r26130-r26097, r26091-r26077, r26073-r26046) +- Fix: Invalidate vehicle colour palette again when rearranging consist, reversing, etc (r26026) +- Fix: [NoGo] Properly validate the range of the growth rate passed to GSTown::SetGrowthRate, instead of masking it to 16 bit (r25966) +- Fix: [Admin] The frame of a command packet was not set for the packets that were sent via the admin interface (r25770) +- Fix: [OSX] The new 10.7 fullscreen code can now also be compiled with older SDK versions [FS#4744] (r25657) +- Fix: Under certain circumstances a track type change would make the end-of-line-is-red setting ineffective [FS#5216] (r25609) +- Fix: Highlight the right entry in the sorting selector in station view window (r25426) +- Fix: Suppress focusing editboxes which are not visible (r25413) +- Fix: Add missing compatibility settings in afterload (r25390) +- Fix: Allow changing GS settings in-game via the AI/GS config window [FS#5507] (r25104) +- Fix: [NewGRF] Do not compare GRF local cargo subtype IDs from different GRFs (r25042) +- Remove: Ordered refit with subtypes, since the cases where it worked were corner cases rather than the general case [FS#3764] (r25041) + + +1.3.3 (2013-11-29) +------------------------------------------------------------------------ +- Fix: Aircraft crashing near the map's border due to a lack of airports could trigger a crash [CVE-2013-6411] [FS#5820] (r26134) + + +1.3.3-RC2 (2013-11-24) +------------------------------------------------------------------------ +- Fix: [Script] Prevent scripts from crashing OpenTTD when they send text with command codes to user editable texts such as sign and station names [FS#5818] (r26093, r26092) +- Fix: Occasional hanging when client joins [FS#5811] (r26043) +- Fix: Multi line text was handled incorrectly causing glitches [FS#5809] (r26037, r26036) + + +1.3.3-RC1 (2013-11-17) +------------------------------------------------------------------------ +- Fix: Crash when the ICU layouter thinks a font is corrupted [FS#5711] (r26029, r26018, r26017, r26016, r26015) +- Fix: Make the installer warning about Windows XP SP3 not trigger on the 64 bit Windows XP which is not really Windows XP to start with [FS#5773] (r26028) +- Fix: Only forward key presses to the IME system if an edit box has the input focus (r26023, r25693, r25691, r25689, r25686, r25684, r25682, r25681, r25667) +- Fix: Having trains miss a platform that is just being modified is less of a problem than having trains stop twice without moving [FS#5684] (r26013) +- Fix: --help text of ./configure for packages that require pkg-config (r26011) +- Fix: The AI/GS library name to use in Import, is not the name given by GetName but GetInstanceName [FS#5662] (r26010) +- Fix: [Windows] Conditional expression with enumeral with non-enumeral type (r26009) +- Fix: Game script showing vehicle on e.g. a goal, then the vehicle being removed and eventually being replaced by a non-user vehicle (most likely smoke) causing an assertion to trigger [FS#5804] (r26007, r26006) +- Fix: Crash when transferring savegame from server to client [FS#5478] (r26005) +- Fix: [OSX] Text input into an edit box would trigger hotkeys [FS#5705] (r26003, r25743, r25671) +- Fix: Comma key collided with F12 key for hotkeys; also remove '+' as that is generally not a key (the '+' on the numpad is a separate one) [FS#5679] (r25973) +- Fix: Rail laying sounds of others could be heard in multiplayer [FS#5665] (r25972) +- Fix: [SDL] Recursive mutex locking when changing blitter [FS#5787] (r25970) +- Fix: The wrong vehicle would be taken in a shared order vehicle list window when the ID >= 65536, causing assertions triggering later on [FS#5800] (r25965) +- Fix: [OSX] Compilation under OSX 10.9 [FS#5797] (r25962, r25951, r25950, r25913) +- Fix: [NewGRF] A powered rail type implies it is compatible as well, but some NewGRF did not state that causing the path reservation code to bail out in some cases because there was no compatible path [FS#5779] (r25961) +- Fix: Temporary persistent storage modifications, e.g. command tests or those from GUI, were not properly reset, creating the possibility of desyncs [FS#5772] (r25956) +- Fix: Train's 'force proceed' status gets reset when the track on the other side of the tile has a signal [FS#5723] (r25955) +- Fix: Wrong signal conversions for savegames from before 0.4.5 [FS#5731, FS#5732] (r25954, r25953) +- Fix: Do not skip numbers when skipping spaces and other sorting 'improving' characters [FS#5719] (r25952) +- Fix: Text direction forcing characters were not filtered out, but shown as ? when ICU was not used for layouting. These are included in chat and console messages to force them to be displayed right [FS#5683] (r25949) +- Fix: NewGRF inspect window in RTL mode (r25943) +- Fix: [NoGo] Preserve the relative town growth progress when changing the town growth rate [FS#5786] (r25931) +- Fix: Several drawing overflows in the signal GUI [FS#5733] (r25929, r25928, r25927) +- Fix: Centre the edit sign window like all query windows (r25918) +- Fix: Initialisation of default objects swapped cost and dates (r25868) +- Fix: Use the actual sprite dimensions for sizing the dropdown arrow of dropdown widgets (r25864) +- Fix: If the child widgets of a NWidgetHorizontal container do not fill the complete container, align them according to text direction [FS#5686] (r25862, r25729) +- Fix: When clearing font cache, also clear layout cache [FS#5737] (r25860) +- Fix: Goto button in order window was not always lowered when it should [FS#5783] (r25858, 25857) +- Fix: Searching for a suitable font failed, if one of the fonts had no '?' glyph, and no baseset is installed [FS#5704] (r25822, r25820) +- Fix: Sprite 0 was considered available, even if no baseset was loaded (r25821) +- Fix: [GS] Language file scanner considered filenames starting with '.' as valid translations, resulting in languages with empty name, which causes trouble [FS#5750] (r25818) +- Fix: [GS] Handle savegames which contain GS translations for languages with empty name more gently [FS#5750] (r25817) +- Fix: [Script] ScriptTile::IsBuildableRectangle could report true for tiles outside of the map, if they happened to wrap around into a valid area [FS#5754] (r25815) +- Fix: [Script] Decoding JSON data with an empty array from Admin port failed (r25809) +- Fix: Ensure the vehicle bar is high enough for the start/stop vehicle graphics [FS#5740] (r25805) +- Fix: Lower sprite and text at the vehicle bar if it is pressed [FS#5739] (r25804) +- Fix: Draw start/stop graphics of the vehicle bar at the right place in RTL mode [FS#5738] (r25803) +- Fix: [NewGRF] Do not allow changing palette when it is set by the NewGRF (r25794, r25793, r25972) +- Fix: Some spelling corrections to Catalan and Latin American town names [FS#5746] (r25775, r25774) +- Fix: If old savegames contain bridges over owned land, keep on drawing the bridges nevertheless [FS#5725] (r25753) +- Fix: Several RTL alignment issues [FS#5692] (r25733, r25732, r25731) +- Fix: NWidgetMatrix used pip_pre and pip_post inconsistently and incorrectly, causing misalignment for RTL [FS#5686] (r25727) +- Fix: Right side of object class string was misaligned (r25726) +- Fix: [OSX] Do not pass -mmacosx-version-min to compilers that do not support it (r25706) +- Fix: Autoreplace/renew also refits free wagons [FS#5700] (r25698) +- Fix: Textbuf caret rendering for complex scripts (e.g. Tamil) (r25696, r25694, r25652, r25651, r25092, r25091) +- Fix: Vehicle::MarkDirty must be called for the front engine [FS#5700] (r25695) +- Fix: [Win32] Several issues regarding conversion of characters (r25677, r25676, r25675, r25674, r25673) +- Fix: [Win32] Handle Unicode characters from outside the BMP correctly (r25672, r25670, r25669, r25668) +- Fix: [OSX] Crash when unhiding the main window [FS#4689] (r25665) +- Fix: [OSX] Bootstrap downloading of a baseset did not work [FS#4847] (r25664) +- Fix: [OSX] Monospace font detection [FS#4857] (r25663, r25662) +- Fix: [OSX] Rework font detection to work even if no default font sprites are present [FS#4847] (r25661) +- Fix: [OSX] The name is OpenTTD, not OTTD (r25660) +- Fix: [OSX] System mouse cursor could become visible during dragging [FS#4420] (r25659) +- Fix: [OSX] The mouse cursor would sometimes jump near the window borders [FS#4392] (r25658) +- Fix: [OSX] The new 10.7 fullscreen code can now also be compiled with older SDK versions [FS#4744] (r25656) +- Fix: [OSX] Mouse cursor was not displayed properly after switching to fullscreen on 10.7+ (r25655) +- Fix: Improve character and word deletion for CJK languages and complex scripts (r25654, r25653) +- Fix: [OSX] Define version constants before they are used (r25643) +- Fix: Some icu_config scripts are too stupid to separate two ldflags by spaces, thus only call it with one (r25642, r25638) +- Fix: Do not suggest a start date for the game when there will be no vehicles available at all (r25640, r25639) +- Fix: City list sort of population and rating are reversed compared to the icon [FS#5666] (r25630) +- Fix: [Script] Give a slightly less generic error when removing nonexistent rail [FS#5651] (r25614) +- Fix: [Script] Do not return ERR_UNKNOWN when trying to move an order to its current location [FS#5648] (r25612) +- Fix: Various misreferences in AI and GS changelog [FS#5649] (r25607) +- Fix: [Script] If a NewGRF returned station type that could not be built by an AI via callback 18, an unknown error would be thrown instead of falling back to the default station [FS#5641] (r25605) +- Fix: Only the front engine's date of last service was updated [FS#5550] (r25604) + + +1.3.2 (2013-07-27) +------------------------------------------------------------------------ +(None) + + +1.3.2-RC2 (2013-07-13) +------------------------------------------------------------------------ +- Fix: [Admin] End-of-rcon data could not be determined reliably for any rcon command [FS#5643] (r25598, r25588, r25587) +- Fix: [Content] When the server closed the connection, the client would for eternity try to read a packet and never timeout making it impossible to reconnect [FS#5635] (r25597) +- Fix: [Script] Changing the script difficulty level in-game would also change the settings using the default even though they were not allowed to change in-game [FS#5644] (r25592) +- Fix: [Admin] Ensure that sent and received length of JSON strings are the same [FS#5646] (r25590, r25589) +- Fix: [Squirrel] Stack overflow did not show an error, due to the stack to throw the error already being full [FS#5320] (r25585) +- Fix: [Script] Documentation implied that XXList::AddItem has a default for value if it is not filled in [FS#5638] (r25579, r25577) +- Fix: Layouter caused significant slowdown with text heavy windows, cache it to make it manageable (r25574, r25570, r25569, r25567, r25564) +- Fix: Make content list appear faster (r25573) +- Fix: Non-ICU layouter started new lines with the space which triggered the linebreak (r25568) +- Fix: If the next order cannot be resolved, reset the current order property instead of leaving it in an intermediate state [FS#5633] (r25562) +- Fix: [Squirrel] Infinite recursion loop in freeing data via a looping set of references [FS#5568] (r25558) +- Fix: One could build bridges over owned land of another company [FS#5524] (r25557) +- Fix: [Script] Texts from scripts were not validated before they were shown, causing an assertion to trigger [FS#5632] (r25555) +- Fix: Provide a warning when no vehicles are available, and tell what to do in that case [FS#5530] (r25553) +- Fix: Possible reading of uninitialised memory due to undefined execution order (r25551) +- Fix: [Windows] Race condition between two drawing threads could crash OpenTTD [FS#5571] (r25550) +- Fix: ICU returns the width of the visual run as if the trailing space was added (in case a newline was added). This caused the width to be more than the requested width, but it would still be drawn correctly [FS#5626] (r25547) +- Fix: Small memory leaks (r25546) +- Fix: [GS] The checks and validations for setting the extra text in the town window became too stringent [FS#5625] (r25544) + + +1.3.2-RC1 (2013-06-30) +------------------------------------------------------------------------ +- Remove: SETX(Y) does not work at all with other than default fonts, so get rid of it (r25454) +- Fix: strndup should not examine strings beyond its upper limit [FS#5621] (r25527) +- Fix: Proper support for Brahmic scripts (e.g. Tamil and Thai) [FS#5481] (r25526, r25525, r25524, r25514, r25513, r25512, r25511, r25501, r25493, r25485, r25483, r25482, r25481, r25478, r25477, r25476, r25474, r25473, r25472, r25471, r25470, r25469, r25468, r25467, r25466, r25465, r25463, r25462, r25455, r25452, r25451, r25450, r25447, r25446, r25445, r25444, r25443, r25442, r25441, r25440, r25439, r25438, r25437, r25436, r25343, r25157) +- Fix: SDL does not give an event when an application gets mouse focus while going to full screen, so manually force the mouse-is-in-window state [FS#5587] (r25523) +- Fix: [NewGRF] When cargo NewGRF define a multiplier to modify vehicle capacities, use the same multiplier to modify loading speed (r25497, r25479) +- Fix: When adding bits to a (train) station, the train trying to stop there could overshoot the (new) stop location and not stop at all [FS#5553] (r25495) +- Fix: The face of the manager differed on clients when the company was started after the clients joined [FS#5610] (r25491, r25490) +- Fix: Do not send encoded texts to names, but decode them into a plain C string and then pass them on [FS#5613] (r25489, r25488) +- Fix: Do not allow control codes in names of things (signs, vehicles, towns, stations, etc), so they have a known maximum fixed size and are, by definition, the same for everyone (r25487) +- Fix: Missing length validation for town and president names in script APIs (r25486) +- Fix: [OSX] OS X SDK versions >= 10.5 always have a non-const iconv declaration (r25480) +- Fix: Disable the depot-refit button in the order GUI, if the consist is not refittable unless it already has a refit order (r25459, r25458, r25457) +- Fix: When town creation failed, removing remnants of the construction failed on protected houses [FS#5603] (r25429) +- Fix: There were two hotkeys to toggle between 'unload' and 'unload if possible' (r25406) +- Fix: The size of station construction windows could oscillate when resizing the window moved the mouse into the window [FS#5596] (r25395) +- Fix: Restrict renaming engines to the server, just like renaming towns (r25394) +- Fix: Loading only 8 bits into a 16 bit variable could cause endianness problems (r25337) +- Fix: Check for zero width space in translations and fail upon finding them [FS#5589] (r25326) +- Fix: [SDL] Keyboard input stopped working after fullscreen toggle [FS#5580] (r25318) +- Fix: Proper size-estimation for numbers with n digits, i.e. not assume a particular number is the widest [FS#5562] (r25314, r25313) +- Fix: Do not focus the editbox in the NewGRF window, if there is no editbox visible (r25307) +- Fix: Game Script APIs that execute a DoCommand were returning the same result as in TestMode during world generation [FS#5561] (r25305) +- Fix: Build railway fences next to objects, even if they are owned by the same company [FS#5565] (r25302) +- Fix: gcc4.6 removed -mno-cygwin option (r25266) + + +1.3.1 (2013-06-01) +------------------------------------------------------------------------ +- Fix: When overbuilding a reserved track with a non-track station tile, that tile would remain reserved and eventually trigger a crash upon removal [FS#5540] (r25251) + + +1.3.1-RC1 (2013-05-17) +------------------------------------------------------------------------ +- Feature: Translations of baseset descriptions via language files (r25209, r25205) +- Feature: Faroese and Scottish Gaelic translations (r25198, r25176) +- Feature: Plural form to be used by Scottish Gaelic (1,11; 2,12; 3..10, 13..19; other) (r25078) +- Change: [strgen] Allow any number of colour codes in translations (r25193, r25192, r25191) +- Change: [Win32] MSVC 2010 comes with stdint.h (r25128) +- Change: Be slightly more lenient with trying to detect a subversion repository in case someone has a sparse tags checkout. In that case the .svn folder misses from the $ROOT_DIR because it is in the $ROOT_DIR/.. (i.e. tags) folder (r25107) +- Fix: 'No station' error was given, even when there was a station that way occupied or not yours [FS#5546] (r25243) +- Fix: Crash when AI is executing a command as it is bankrupted (removed from the game) [FS#5547] (r25236) +- Fix: Give bridges owned by no one (from bankrupt companies) to the first company which replaces the bridge. Everyone could have removed/rebuild the bridge anyway [FS#5541] (r25231, r25227) +- Fix: [NewGRF] Revise when vehicle running sound effects 04, 07 and 08 are played; in depot or tunnel, or when crashed or stopped: No sound. Braking: Effect 08 instead of 07 [FS#5538] (r25226) +- Fix: [NewGRF] Play vehicle sound effect also for planes (r25225) +- Fix: [NewGRF] cur_speed is only valid for the front engine, so make other engines in the consist use the speed of the front [FS#5534] (r25224) +- Fix: [NewGRF] Make tick_counters work the same for vehicles (r25223, r25222) +- Fix: [NewGRF] IsCompatibleTrainStationTile() is not a symmetric function. Clarify the parameters and fix the cases were they were swapped (r25221) +- Fix: Consider map border as water with respect to river/canal continuation (r25220) +- Fix: [Script] Clarify on which tiles IsDesertTile and IsSnowTile work, i.e. the ones without infrastructure or buildings, and introduce GetTerrainType for the cases where IsDesertTile/IsSnowTile do not work [FS#5537] (r25213) +- Fix: The level crossing sound is an ambient sound and not a new year sound (r25200) +- Fix: Original train and road vehicle acceleration did no longer respect bridge speed limits [FS#5523] (r25167) +- Fix: [Win32] Do not statically link to SHGetFolderPath as it may not exist, and improve its emulation [FS#5522] (r25155, r25153) +- Fix: [Win32] Do not store invalid paths in the search path list (r25154) +- Fix: Remove stray reservation from savegames affected by FS#5510 et al. upon loading [FS#5520] (r25152) +- Fix: [Script] XXBase::Chance function did not work for large values (>65535) [FS#5517] (r25148) +- Fix: Several typos/inconsistencies in English strings [FS#5496] (r25144, r25143) +- Fix: When extra dynamite was disabled, towns would be allowed to clear bridges with trams (r25141) +- Fix: Towns are build as OWNER_TOWN, so they also need to be removed as OWNER_TOWN otherwise parts might remain [FS#5519] (r25140) +- Fix: Editboxes could become too small when resizing windows (r25121) +- Fix: Game script language files did not work, when inside a tar [FS#5509] (r25117, r25114) +- Fix: [NewGRF] Acceleration of NewGRF aircraft was too fast, while acceleration of default aircraft was way too slow (r25115) +- Fix: Pass $LDFLAGS_BUILD to all endian_check compilations (r25108) + + +1.3.0 (2013-04-01) +------------------------------------------------------------------------ +- Fix: Station rebuilding could leave reserved tiles which caused crashes later on [FS#5510, FS#5516] (r25132) +- Fix: When the count for a scrollbar was 0, the inter distance was subtracted too much causing a scrollbar with a negative size (r25123) + + +1.3.0-RC3 (2013-03-18) +------------------------------------------------------------------------ +- Fix: Limit aircraft property 0D to 19, since the conversion result to km-ish/h needs to fit into a byte [FS#5492] (r25099) +- Fix: Clicking the statusbar crashed, when news were pending but no news were shown yet [FS#5486] (r25093) +- Fix: Make editbox character filters also apply to pasted content from clipboard (r25090, r25089) +- Fix: Catch exception anonymously, if the exception content is not of interest [FS#5500] (r25081) + + +1.3.0-RC2 (2013-03-05) +------------------------------------------------------------------------ +- Fix: Make sizes of the station preview list and direction selection identical in the station build window [FS#5472] (r25064) +- Fix: When allocation of the sprite cache fails, try to allocate less memory and display an error message later on (r25061) +- Fix: Refactor Script Debug GUI to only set widget states in OnInvalidateData [FS#5490] (r25052) +- Fix: Do not let gcc include files from the 'standard C' include directories to avoid inclusion of header files at the top of the preprocessed nfo files, which cause NFOrenum/GRFcodec to make invalid assumptions about the NFO version (r25050) +- Fix: Minimise gaps feature caused removal to only happen at the signal build interval instead of the implicit interval of 1 [FS#5479] (r25038) +- Fix: Green path signals would be shown when building them 'under' a train, and they would keep showing green until they were passed again [FS#5480] (r25037) + + +1.3.0-RC1 (2013-02-19) +------------------------------------------------------------------------ +- Feature: Searching of (missing) content via GrfCrawler (r25024, r25023) +- Change: Cleanup goals and cargo monitors of companies when they go bankrupt or are taken over (r24986) +- Change: Apply the same name sorting rules to content and NewGRF list as for the server list (r24983) +- Fix: [SDL] Crash after bootstrap download of 32bits base set due to referencing a deleted mutex [FS#5466] (r25017) +- Fix: [SDL] Improve 8bpp hardware palette support. Instead of always requesting SDL_HWPALETTE, it is now only done for 8bpp blitters in fullscreen mode (r25003, r25002, r24993) +- Fix: Set vehicle's service interval is percent flag appropriately on creation [FS#5137] (r24998) +- Fix: When choosing a train in a depot to attach a newly purchased wagon to, do not consider trains currently moving in and out of the depot (r24987) +- Fix: [Script] Crash when passing too many parameters [FS#5465] (r24982, r24981, r24980) + + +1.3.0-beta2 (2013-02-07) +------------------------------------------------------------------------ +- Feature: [NewGRF] Station randomisation triggers (r24906, r24905) +- Feature: Settings type filter included in the advanced settings GUI (r24862, r24863) +- Change: Revert to opening the vehicle GUI again when cloning vehicles using the clone-button from the depot GUI [FS#4458] (r24955) +- Fix: Additional zoom in levels could glitch by a few pixels due to incorrect rounding [FS#5463] (r24975) +- Fix: Honour pause_on_newgame setting when running as a dedicated server [FS#5279] (r24974) +- Fix: [NewGRF] Prevent access to tile-based variables when tile is invalid [FS#5462] (r24973) +- Fix: Do not make overbuilding rivers with canals insanely expensive [FS#5258] (r24972) +- Fix: Crash when an infinite loop occurred during loading of a script [FS#5346] (r24970) +- Fix: company window was not updated when shares were enabled/disabled [FS#5379] (r24968) +- Fix: Trams would get stuck on water [FS#5228] (r24966) +- Fix: With YAPF the docking behaviour differed per direction; now favour docking in the direction you approached [FS#5416] (r24964) +- Fix: Do not stop loading if there are reservations left [FS#5435] (r24963) +- Fix: Reserve all capacity while unloading to avoid 'stealing' cargo, i.e. loading cargo onto a second vehicle when the first cannot be fully filled yet [FS#5438] (r24962) +- Fix: If a platform is enlarged and there is a reservation, reserve the whole platform [FS#5362] (r24961) +- Fix: Inconsistencies in the 'thanks to' lists [FS#5423] (r24960) +- Fix: Set 'replace when old' flag when replacing an autoreplace (r24950) +- Fix: Deleting implicit orders was not able to deal with the various side-effects of DeleteOrder [FS#5452] (r24944) +- Fix: Redraw autoreplace window properly in network games (r24939) +- Fix: Never put a space between cargo name and subtype [FS#5447] (r24938) +- Fix: Do not allow order refit to be set for no-load orders [FS#5446] (r24936) +- Fix: Make group names unique per company and vehicle type [FS#3473] (r24933) +- Fix: Prevent more NewGRFs being selected than is possible to load [FS#5158] (r24932) +- Fix: [GS] Do not try to pause or unpause crashed scripts [FS#5415] (r24929) +- Fix: [Squirrel] Update line information before processing 'while' token of 'do'-'while' statement [FS#5408] (r24928) +- Fix: Add a tooltip to the mapsize selection mentioning possible deviations [FS#5395] (r24925) +- Fix: When an object built on a river is removed, restore the river [FS#5441] (r24923) +- Fix: Upgrading bridges could steal road types [FS#5389] (r24912) +- Fix: [GS] Allow GSs to pass negative integer string parameters (r24908) +- Fix: 'Train loads/unloads cargo' station animation triggers on individual platform (r24904) +- Fix: Cached station animation triggers were only set when removing parts of a station (r24903) +- Fix: The station build window did not update when the station spread changed [FS#5434] (r24899) +- Fix: Do not unpause the game when closing the highscore window if it was already paused before the highscore screen was shown (r24898) +- Fix: Improvements and fixes for the base translation [FS#5411, FS#5420, FS#5421, FS#5422, FS#5427] (r24896, r24875, r24872, r24869) +- Fix: Allow downgrade of road bridges in the scenario editor [FS#5436] (r24895) +- Fix: Invalidate station selection window when station spread changes [FS#5434] (r24894) +- Fix: Distribute GS compat_.nut with OpenTTD (r24890) +- Fix: Pass proper UTF-16 strings instead of UCS-2 to ICU in order to preserve characters outside the BMP (r24885) +- Fix: A completely emptied vehicle could trigger an assert (r24883) +- Fix: Desync when NewGRF changes the stats related to acceleration (power, weight, tractive effort, etc) during service or 32 day triggers (r24882) +- Fix: Incorrect Romanian own name (r24874) +- Fix: Make invalid sprite references to mapgen sprites behave the same as invalid references between recolour and real sprites [FS#5404] (r24858) +- Fix: Do not let UFOs and coal mines clear water (r24857) +- Fix: Do not let UFOs and coal mines destroy depots [FS#5406] (r24856) +- Fix: Do not send aircraft to depots that are out of range of the next destination [FS#5405] (r24855) +- Fix: Only consider vehicles available in the climate for purchase/depot cell size (r24854) +- Fix: Extend widget data member to 32 bits so that sprite IDs >= 2^16 can be used (r24853) + + +1.3.0-beta1 (2012-12-24) +------------------------------------------------------------------------ +- Feature: Advanced settings to disable certain sound effects (r24846) +- Feature: [NewGRF] Support oversized purchase list sprites [FS#5271] (r24839) +- Feature: Improve pylon placement around station tiles that display neither pylons nor catenary (r24836) +- Feature: When using a non-release version of OpenTTD and the basegraphics are missing some sprites, also suggest to use a non-release version of the basegraphics (r24821) +- Feature: Consider engine preview windows always sticky, so non-shift mass-closure does not affect them [FS#2632] (r24809) +- Feature: When share-cloning vehicles do not open the vehicle window of the new vehicle [FS#4458] (r24808) +- Feature: Enable usage of 'companies' console command also in singleplayer [FS#2820] (r24807) +- Feature: Ask for confirmation before creating giant screenshots [FS#3148] (r24806) +- Feature: Separate subdirectory for screenshots (r24804) +- Feature: Unify the difficulty settings window with the advanced settings window (r24791, r24792) +- Feature: Various methods to open the OSK (r24785) +- Feature: Add a string filter to the server list [FS#3852] (r24769) +- Feature: Add industry type and cargo dropdown selection for easier navigating in the industry chain window (r24763) +- Feature: Introduce GUI icons for deleting to the left/right (r24749) +- Feature: Add clear button to all editboxes (r24748) +- Feature: Reset the vehicle engine pool when starting a scenario (r24716) +- Feature: Add basic/advanced/expert filters to the advanced settings GUI [FS#5355] (r24671) +- Feature: Draw cargo labels in the station list black or white depending on the background colour [FS#5311] (r24668) +- Feature: Do not display the preview window for disabled vehicle types (r24660) +- Feature: Add new filter option to the advanced settings window to show only changed settings (r24647) +- Feature: Add text filtering to advanced settings (r24632) +- Feature: Add buttons to expand/collapse all to advanced settings GUI (r24631) +- Feature: [GS] Allow GameScripts to construct and prospect industries without having a sponsor (r24623) +- Feature: Pay interest also on a negative cash value (r24618) +- Feature: Sort cargo filter by cargo name/label at the company stations window [FS#5311] (r24615) +- Feature: More options for the auto-scroll setting (r24590) +- Feature: Allow AI/GS script developers to break the execution of their scripts and pause the game using ScriptController::Break() (r24542, r24575) +- Feature: Scripts can be suspended even if the game is still progressing, thus break-on-log now works also for Game Scripts (r24537) +- Feature: Highlight industries on the smallmap when the mouse is over an entry in the legend (r24534) +- Feature: [NewGRF] Allow resolving var 5F via vehicle var 61 (r24527) +- Feature: [OSX] Additional high-resolution icons for the app bundle [FS#4539] (r24525) +- Feature: Ctrl+Backspace/Delete to remove characters up to next word beginning in text edit boxes [FS#5203] (r24521) +- Feature: Ctrl+Arrow keys to move entire words in text edit boxes [FS#5203] (r24520) +- Feature: When using autorefit only load/refit vehicles if other wagons cannot already take all cargo without refitting [FS#5106] (r24497) +- Feature: [GS] Useful behaviour for GSEngine::IsValidEngine and GSEngine::IsBuildable when outside GSCompanyMode scope (r24492) +- Feature: Display GS dead state in AI debug window [FS#5230] (r24489) +- Feature: Add buttons to view textfiles from the online content window [FS#5236] (r24488) +- Feature: Make the pathfinder decide whether ships shall leave depots towards north or south [FS#5127] (r24481) +- Feature: [GS] API compatibility scripts for Goal Scripts [FS#5219] (r24468) +- Feature: Display in the advanced settings description a setting type which explains the scope of changes to a particular setting [FS#5244] (r24411) +- Feature: [GS] Allow game scripts to monitor cargo pickups and deliveries done by companies (r24406) +- Feature: [NewGRF] Allow vehicle variable 61 for callback 2D (recolour) and re-randomisation (r24371) +- Feature: [NewGRF] Customisable signals for rail types (r24367) +- Feature: Allow filtering for multiple words (separated by whitespace resp. quoted) in script breakpoints, the sign list, content and NewGRF-GUIs (r24337, r24342) +- Feature: Add dropdowns to NewGRF configurations, if all values have labels (r24318) +- Feature: Add dropdowns to AI configurations, if all values have labels (r24317) +- Feature: Allow to select advanced settings with limited range with a dropdown list (r24316) +- Feature: Display default values for advanced settings in the settings description (r24298) +- Feature: News item for exclusive transport rights [FS#2688] (r24287) +- Feature: [GS] Additional GSNews::NewsItem::NewsTypes (r24286) +- Feature: [NewGRF] Variable with the current max speed for vehicles [FS#5052] (r24246) +- Feature: Descriptions explaining the meaning of advanced settings (r24237) +- Feature: Split the renew-months setting text in two string values (one before life time and one after) (r24210) +- Feature: Show a hint in the supplies tab of station windows, if the station is affected by exclusive transport rights [FS#5178] (r24205) +- Feature: [NewGRF] Callback to set industry production level on construction (r24186) +- Feature: South Korean and South African currencies [FS#4907] (r24148) +- Feature: Randomise count of passengers killed in a crash [FS#3576] (r24142) +- Feature: Display rating in the town directory window (r24141) +- Feature: Show group name in the replace vehicle window caption [FS#1117] (r24140) +- Feature: Allow to create a new vehicle group by drag and drop (r24139) +- Feature: Ctrl+Drag to add all vehicles with a shared order list to a group (r24138) +- Feature: Draw indicator icon in the replace vehicle window for vehicles which have a replacement set (r24137) +- Feature: Autoreplace vehicles only when they get old [FS#4465] (r24136) +- Feature: Add configurable limits for tree planting, and remove tree drag size limit (r24134, r24135) +- Feature: Lithuanian currency [FS#4984] (r24133) +- Feature: Ctrl+Clicking to change colour of all colour schemes at once [FS#1952] (r24131) +- Feature: Deselect 'remove' button when changing signal types in the GUI [FS#2314] (r24130) +- Feature: Option to minimise signal distance when dragging over obstacles [FS#3660] (r24129) +- Feature: Allow closing airports for incoming aircraft [FS#1497] (r24127) +- Feature: Drag and drop support for the NewGRF list window [FS#3854] (r24126) +- Feature: Drag destination highlighting to the group GUI [FS#3705] (r24125) +- Feature: [NewGRF] Misc engine flag to disable breakdown smoke [FS#4658] (r24124) +- Feature: Be more careful with the population of a small town while placing a statue (r24105) +- Feature: Debug option for showing the redrawn dirty blocks/rectangles [FS#5101] (r24065) +- Change: News display options are now shown in the advanced settings window (r24842, r24843, r24844, r24845) +- Change: Drop 'signal density' from the advanced settings GUI. It is more suited to be only changed via the signal GUI (r24670) +- Change: Check for bankruptcy on a monthly basis (r24619) +- Change: Only bankrupt, if you have negative money considering you took max loan (r24617) +- Change: When building long roads or tramways, only build the roadbits at the beginning and the end if they can connect to something [FS#5228] (r24503) +- Change: Disallow original and better road layouts to build roads under bridges along the bridge direction [FS#5229] (r24391) +- Change: Allow cloning of orders which are unreachable for the destination vehicle if they were already unreachable for the source vehicle [FS#5213] (r24390) +- Change: Allow building/modifying/removing signals even if a train is on the belonging track (r24356) +- Change: [NewGRF] Make bounding boxes of road vehicles change according to the vehicle length to make alignment easier [FS#5204] (r24331) +- Fix: [NewGRF] Consider regearing-like cargoes as no-cargo in cargo filters [FS#5386] (r24848) +- Fix: [NewGRF] Draw NewGRF railtypes in NewGRF station previews (r24840) +- Fix: Do not consider blocked rail station tiles that display wires as non-reachable for masking out unnecessary catenary wires (r24837) +- Fix: The autorefit dropdown in the order GUI was not always updated when modifying vehicle consists [FS#5396] (r24834) +- Fix: [NewGRF] Incorrect values are better than a crash when a NewGRF queries vehicle variable 4C before vehicle initialisation is completed [FS#5398] (r24831) +- Fix: determineversion.vbs could hang in a git checkout (r24826) +- Fix: Close pending preview windows when the engine is introduced to everyone (r24812) +- Fix: Close engine preview window when another client accepts it (r24811) +- Fix: Make engine preview offers more robust with regard to changes in the company ranking (r24810) +- Fix: When displaying the previous news message, do not consider news which are turned off [FS#4224] (r24802) +- Fix: Glitch in timetable GUI [FS#5327] (r24800) +- Fix: Unify checks for editability of settings (r24787) +- Fix: Invert the focus handling of the OSK. Keep the focus at the OSK and close it on losing focus (r24774) +- Fix: Shift in the OSK behaved like capslock (r24773) +- Fix: [Win32] Do not crash when switching to an unsupported fullscreen display mode (like 8bpp modes in Windows 8) [FS#5359] (r24762) +- Fix: Crash on corrupted savegame [FS#5367] (r24754) +- Fix: Some editboxes had a different colour than the rest of the window (r24747) +- Fix: In various windows the OSK looked shiny but using it had no effect whatsoever (r24727) +- Fix: AI debug GUI crashed when using disabled buttons via hotkeys (r24723) +- Fix: When starting a scenario apply the local company settings to the new company [FS#5139] (r24717) +- Fix: [NewGRF] Allow stations to draw snow/desert aware ground sprites with railtype overlays [FS#5335] (r24715) +- Fix: [NewGRF] Draw default foundations if resolving of custom station foundation sprites fails [FS#5337] (r24714) +- Fix: [NewGRF] Tolerate old NewGRFs returning invalid values via CB 11 [FS#5262] (r24713) +- Fix: [NewGRF] Station variables 61 and 62 returned incorrect values, if no vehicle ever tried loading [FS#5303] (r24712) +- Fix: Check whether to not display a ^ loading indicator at drop stations only worked if there was no other vehicle unloading for 255 ticks (r24711) +- Fix: [NewGRF] Station var 48 should report acceptance, not supply (r24706) +- Fix: Station rating might consider very old vehicles very young (r24705) +- Fix: Disallow closing oilrig airports in the scenario editor (r24703) +- Fix: Workaround for an overoptimisation done by GCC 4.5 [FS#5246] (r24701) +- Fix: Get packing right on MinGW GCC 4.7 (r24573) +- Fix: Make sure all template functions are instantiated by at least one compilation unit [FS#5276] (r24496) +- Fix: Do not load order backups when loading a server-saved game in single player (r24445) +- Fix: Allow overbuilding bridges with the same type when adding a roadtype [FS#5221] (r24413) +- Fix: Cargo lists cannot have genders (mostly because it is very unclear what gender it would have) (r24374) +- Fix: Off by one errors with regard to clicking on setting buttons (r24313) +- Fix: STRING1 probably means STRING1 (r24295) +- Fix: squirrel_export should match key words like 'virtual', 'static' and 'const' only as whole words (r24288) +- Fix: Hide object specs/classes from the GUI, if they will never be available to the user [FS#4967, FS#5120] (r24171) +- Fix: Unify the spacing in 'AI/Game Script' and never just say 'Game' when 'Game Script' is meant [FS#4898] (r24020) + + +1.2.3 (2012-11-01) +------------------------------------------------------------------------ +(None) + + +1.2.3-RC1 (2012-10-17) +------------------------------------------------------------------------ +- Change: [NewGRF] Set the reference brightness of 32bpp mask recolouring to 128 (r24610) +- Fix: Configure script did not properly handle _BUILD flags during reconfigure (r24601) +- Fix: Configure script failed to detect libfontconfig 2.10 as newer than 2.3 (r24598) +- Fix: When fontconfig is not available, the bootstrap download crashed [FS#5336] (r24597) +- Fix: Crash when a gamescript provided too many parameters to a GSText object [FS#5333] (r24593) +- Fix: [Script] API documentation mistakes/omissions (r24584) +- Fix: Do not add duplicates to the ban list [FS#5308] (r24580) +- Fix: Draw the window resize sprite bottom-aligned [FS#5324] (r24577) +- Fix: Vehicle list at buoys did no longer work [FS#5319] (r24576) +- Fix: [Windows] Do not cast away const in OS specific code (r24572, r24571) +- Fix: Naming of bundles was somewhat broken (r24569) +- Fix: Non-train vehicle lists were not resorted when vehicles were renamed [FS#5261] (r24567) +- Fix: Stop both price and payment inflation if either of them has reached MAX_INFLATION (r24565) +- Fix: Limiting the inflation did not quite work [FS#5312] (r24564) +- Fix: Do not show profit from refits as cost in the refit window [FS#5297] (r24544) +- Fix: Do not limit to reading one UDP packet per game loop (r24532) +- Fix: Max script chance was too big (r24531) +- Fix: [NewGRF] RandomAction 84 should interpret register 100 as signed (r24528) +- Fix: [OSX] Some compile problems in mac-only code [FS#5296] (r24524) +- Fix: The gender of an industry name is defined by the industry-type part of the name, not by the town-name part, even if it comes first (r24523, r24522) +- Fix: GStexts were compiled incompletely when containing certain string codes (r24516, r24515) +- Fix: The mousewheel did not work in the build waypoint window [FS#5285] (r24507) +- Fix: [NewGRF] Airport variables 60 to 65 and 69 used the wrong cargo translation table for translations (r24506) +- Fix: Do not show the global goals as company goals for spectators (r24500) +- Fix: Clarify description of command line option -n (r24485) +- Fix: Do not call RebuildSubsidisedSourceAndDestinationCache() before subsidy savegame conversion is finished [FS#5232] (r24482) +- Fix: Trains were unable to reverse in stations when using NPF (r24479) +- Fix: The --xxx yyy format (instead of --xxx=yyy) for configure did not work (r24471) +- Fix: --prefix was not accepted by configure (r24470) +- Fix: Changing auto-refit for a 'goto station' order was inadvertently modifying the full load state [FS#5264] (r24457) + + +1.2.2 (2012-08-16) +------------------------------------------------------------------------ +(None) + + +1.2.2-RC1 (2012-08-01) +------------------------------------------------------------------------ +- Fix: In some cases ships could be covered with land [CVE-2012-3436] [FS#5254] (r24449, r24439) +- Fix: Copy constructor and assignment operator cannot be implicit template specialisations [FS#5255] (r24448) +- Fix: Make (non-refittable) vehicles with invalid default cargo unavailable [FS#5256] (r24438) +- Fix: CFLAGS/CXXFLAGS ignored for helper binaries (r24432, r24429, r24427, r24365) +- Fix: [Windows] Unbreak NewGRF MD5 sum calculation. Macros and side effects do not mix, especially if there is some obscure '#define min' in a windows header that nobody thinks of [FS#5231] (r24416) +- Fix: Disallow removing roadtypes from bridges when not dragging in bridge direction [FS#5221] (r24414) +- Fix: Draw wires under low bridges if the bridge is transparent, not if the wire is transparent (r24403) +- Fix: Station properties 11 and 14 were combined incorrectly [FS#5243] (r24402) +- Fix: [Windows] Changing resolution did not resize the window (r24394) +- Fix: Use the 'all vehicles' group for the autoreplace window from the vehicle list [FS#5239] (r24392) +- Fix: Do not consider not finding a particular base set critical; just load a different one and display an in-game error later on [FS#5233] (r24388) +- Fix: Make IsInDepot() functions behave consistent across vehicle types and add IsChainInDepot instead, if that is what shall be checked [FS#5188] (r24384) +- Fix: Call Vehicle::IsStoppedInDepot only for the first vehicle in a chain (i.e. primary vehicle or free wagon) (r24382) +- Fix: Do not resize the object GUI when selecting objects. Rather clip the object name (r24379) +- Fix: ReInit could crash for windows with NWidgetMatrix widgets [FS#5218] (r24378) +- Fix: [NewGRF] Extended action A1 did not work correctly [FS#5227] (r24369, r24361) +- Fix: [NewGRF] Ship-specific 80+x variables were missing for unknown reason [FS#5224] (r24360) +- Fix: When airport construction was denied due to noise, the error message named the wrong town (r24354) +- Fix: [NoAI] A TileIndex is not a station id, so do not use it as one [FS#5215] (r24353) +- Fix: When highlighting the drop position for vehicles in depots, make space for all articulated parts (r24352) +- Fix: Short vehicles were not properly positioned at the cursor when dragging for RTL languages (r24351) +- Fix: EQUALSIZE widget containers within EQUALSIZE containers were initialised with wrong sizes (r24346) +- Fix: The cursor in the company password window was not blinking due to wrong magic constants (r24335) +- Fix: [NewGRF] Change the length of 8/8 road vehicles in vehicle lists to 32 pixels; this is in fact the correct length as can be seen in corners for short articulated parts following each other [FS#2553] (r24332) +- Fix: [NewGRF] Group vehicles in the purchase list properly by source GRF, but also consider engine GRFID overrides [FS#4254] (r24330, r24321) +- Fix: Make the AI settings window behave more like the other settings window by closing the query window whenever selecting a different row (r24315) +- Fix: Editing NewGRF parameters using the query window showed wrong values, if there was no direct relation between parameter index and parameter register (r24314) +- Fix: Centre object previews in 1- and 2-view selectors based on the 4-view selector layout [FS#5057] (r24299) +- Fix: Increase the left and right margins of the text in the yes/no query window (r24293) +- Fix: [NewGRF] GetReverseCargoTranslation() was unnecessary complicated and also returned the wrong thing for cargoes not present in the translation table (r24273) +- Fix: [NewGRF] Load cargo- and railtype-translation during both reservation and activation stage. That way they can be selected using Action7 depending on present cargo- or railtypes (r24272) +- Fix: Use the same colour scheme for the script selection window as in other comparable windows (r24268) +- Fix: Make the oilrig-vehicle list accessible to spectators and colour its caption neutrally grey [FS#5126] (r24260) + + +1.2.1 (2012-06-01) +------------------------------------------------------------------------ +- Fix: [Script] ScriptTown::GetGrowthRate() returned wrong values after usage of SetGrowthRate() (r24302) + + +1.2.1-RC1 (2012-05-16) +------------------------------------------------------------------------ +- Fix: Change the unit of the sprite-cache size setting from megabytes to megapixels, so it depends on the blitter being used. Also increase it from 64 to 128, and change the name in the cfg file, so everyone gets the new default [FS#5162] (r24252) +- Fix: Do not immediately display error messages from parsing the cfg file, but schedule them for displaying after the GUI is prepared for it [FS#5154] (r24250, r24249, r24248, r24247) +- Fix: Dereferencing uninitialised pointer causing a crash [FS#5159] (r24224) +- Fix: Lag counters were not properly reset when switching states making it possible to get disconnected for lagging when you were not lagging [FS#5166] (r24221) +- Fix: Adopt ICU version detection to also deal with the new versioning scheme since ICU 49 [FS#5182] (r24220) +- Fix: Immediately do the cargo payment on vehicle crashes instead of when they are cleared [FS#5152] (r24219) +- Fix: The confirmation window to abort world generation was hidden during world generation, so actually you could not abort it [FS#5159] (r24214) +- Fix: If a company is taken over or bankrupts, transfer exclusive transport rights to the new owner respectively cancel them (r24204) +- Fix: Make the engine name not overdraw the engine count in the autoreplace GUI (r24203) +- Fix: Make the size of the details in the autoreplace GUI match more the size of the details in the purchase list (r24202) +- Fix: Mark group list dirty when setting/clearing autoreplace for an engine type [FS#5170] (r24201) +- Fix: Invalidate build vehicle windows every month, in case they need resorting due to changed reliabilities [FS#5149] (r24200) +- Fix: If you consider a settings to potentially cause desyncs via NewGRFs and thus disallow changing it in network games, you should probably also sync it to clients (r24193, r24191) +- Fix: Use default value when reading an invalid setting value [FS#5153] (r24192, r24146) +- Fix: [Windows] When going to fullscreen and back, restore to the resolution you were, not to the fullscreen resolution (r24189) +- Fix: [Windows] When changing the basics of a window (fullscreen, 8bpp/32bpp), and a window already exists, it was forced out of maximise mode, and its resolution/position was reset, often causing unwanted side-effects [FS#5151] (r24188) +- Fix: Town radii were not updated immediately after construction/destruction of houses, resulting in desyncs [FS#5169] (r24183) +- Fix: The population of a town was computed incorrectly for overridden houses when loading a game (r24182, r24181, r24179) +- Fix: The object name from property A was not displayed in the object GUI [FS#5110] (r24178) +- Fix: The arctic 'shops and offices' used the 'church' sprite in one of its four views [FS#5148] (r24177) +- Fix: The object GUI did not draw objects when all objects of a class are disabled (r24176) +- Fix: If you spent hard work on finding an available object ID, you should probably also use it instead of always 0 (r24159) +- Fix: Town producing no cargo at all could spawn passenger subsidies (r24158) +- Fix: The music volume was set too early during startup causing it to be not set correctly (r24155) +- Fix: [Squirrel] Crash when trying to create an array with negative size [FS#5160] (r24153) +- Fix: [NoAI] Do not return the last 'cached' speed of vehicles when they are stopped/crashed [FS#5157] (r24152) +- Fix: [Script] Typo in script documentation (r24151) +- Fix: Glass-sprite of bubble-generator was not drawn anymore for completely constructed tiles [FS#5143] (r24107) +- Fix: Conflicting strategies for resizing the main toolbar and statusbar after resizing the main window [FS#5136] (r24089) +- Fix: Significantly reduce the area that is redrawn for text effects [FS#5103] (r24068) +- Fix: Do not redraw up to 25% of the map when making a new vehicle visible for the first time (r24067) +- Fix: Do not redraw the text effect when nothing changed (r24066) + + +1.2.0 (2012-04-15) +------------------------------------------------------------------------ +- Fix: When starting GS or AI, always use the settings of the game, not the new-game settings [FS#5142] (r24108) +- Fix: Provide translated comments in the desktop file without language name postfix (r24100) +- Fix: Cloning orders of aircraft with limited range failed [FS#5131] (r24086) + + +1.2.0-RC4 (2012-04-01) +------------------------------------------------------------------------ +- Fix: Reversing trains while they were entering or leaving a depot could lead to stuck trains [FS#5093] (r24078, r24071) +- Fix: The 'last joined' server was not properly selected anymore [FS#5098] (r24070) +- Fix: Immediately start querying the last joined server instead of waiting for the requery loop [FS#5097] (r24069, r24062) +- Fix: Make the full snowiness level of houses the same as roads and rails [FS#5121] (r24064) +- Fix: With certain versions of GCC and compiler flags the compiler could reorder some code badly causing the 32bpp depot flag not working [FS#5125] (r24063) +- Fix: Do not freeze aircraft mid-flight when skipping to an out-of-range destination [FS#5123] (r24060) +- Fix: Wrong numbering of string parameters causing wrong capacities to be shown [FS#5124] (r24058) +- Fix: Crash when timetabling a maximum travel speed of 0 [FS#5111] (r24053) +- Fix: [NewGRF] Imported GRF sounds were inserted into the wrong slots [FS#5107] (r24052) +- Fix: [NewGRF] Realsprites inside the action 11 block were not skipped correctly (r24050) +- Fix: Improve error messages for the placement restrictions of banks, water towers and toy shops [FS#5095] (r24040) + + +1.2.0-RC3 (2012-03-18) +------------------------------------------------------------------------ +- Feature: Allow display of baseset textfiles (r24037) +- Feature: Increase the station class limit from 32 to 256 (r24031) +- Fix: After opening a text window with the monospaced font, all other text started glitching (r24038) +- Fix: [NoAI] Reset 'is random' status of temporary variable during saveload as it is not always written to when loading an AI which means it would be taking the 'is random' setting of another AI (r24033) +- Fix: [NoAI] Make AIEngine::IsArticulated return true if the articulated callback flag is set, do not try to run the callback (r24029) +- Fix: Pass cases down into the list of cargoes [FS#5090] (r24024, r24023, r24022) + + +1.2.0-RC2 (2012-03-04) +------------------------------------------------------------------------ +- Fix: [Script] AI used in names in API for GSOrder [FS#5088] (r24006) +- Fix: Improve rounding when converting display speeds to internal speeds [FS#5079] (r23995) +- Fix: Also reset the font glyph cache when switching blitters (r23992, r23987) +- Fix: [NewGRF] Also display the cargo subtype for vehicles which have no capacity, but a subtype [FS#5076] (r23991) +- Fix: Zero the offsets of disabled zoomlevels, so they do not influence offset calculations (r23989) +- Fix: Invalid reads when scaling an odd-sized sprite smaller (r23986) +- Fix: Inconsistent quit/abandon/exit game/scenario/editor strings [FS#5074] (r23985) +- Fix: Fix the order of lights on the helipad [FS#5082] (r23984) +- Fix: Tarred heightmaps would not be found [FS#5083] (r23983) +- Fix: Do not load a game during UpdateWindows as that might trigger changing the blitter which triggers re-entrant locking (r23980, r23977) +- Fix: [SDL] Palette update was done too late making switching from 8bpp -> 32bpp look ugly (r23978) +- Fix: Sprites of different zoom levels were not always padded correctly to a common size (r23976) +- Fix: Also save the maximum travel speed for the current vehicle order (r23973) + + +1.2.0-RC1 (2012-02-19) +------------------------------------------------------------------------ +- Feature: [NewGRF] Customisable tunnel portals for rail types (r23952) +- Feature: Timetabled maximum travel speeds for non-flying vehicles (r23947) +- Feature: Readme/licence/changelog viewer for AI and game scripts [FS#5047] (r23936) +- Feature: [NewGRF] 32bpp sprites in GRFs (r23897) +- Feature: [NewGRF] Support for RealSprites with multiple zoom levels (r23890) +- Feature: [NewGRF] Support for container version 2 (r23887) +- Fix: Refittability should never depend on the current capacity of a vehicle [FS#5070] (r23965) +- Fix: Do not look for missing sprites twice during startup [FS#5072] (r23963) +- Fix: [Script] Infinite recursion within a script was not caught properly, so they could cause crashes of OpenTTD instead of the AI [FS#5068] (r23962) +- Fix: [NewGRF] Make the properties for always/never refittable cargo types not behave incremental, but reset them on reassignment (r23960) +- Fix: [Network] Do not allow chat messages from pre-active clients. As they have not got the savegame yet, they will not have the interface to send them either (r23958) +- Fix: [Network] Allow sending chat to pre-active clients as the clients start accepting once they send 'map ok' to the server, which is the same moment we change their status to pre-active [FS#4990] (r23957) +- Fix: When the population of a town changes the town view might even have to change size due to different cargo requirements [FS#5062] (r23953) +- Fix: [NoGo] Never show GSGoal::Question() to spectators [FS#5063] (r23950) +- Fix: Better rounding when converting internal speed to displayed speed (r23945) +- Fix: Also list DEITY signs in the signlist in the scenario editor [FS#5061] (r23943) +- Fix: Infrastructure cache of standard road stops would get messed up when buying a company with them (r23942) +- Fix: Scale infrastructure cost of rail tracks by the total number of all tracks and not independently for each rail type (r23931) +- Fix: [Script] Do not close the parameter window when a script starts [FS#4944] (r23930) +- Fix: Do not accelerate, for smoke purposes, when you reached the track's maximum speed [FS#5053] +- Fix: 32bpp animated blitter was optimised a bit too far regarding not needing to update the colour mapping when (re)initialising the palette [FS#5056] (r23927) +- Fix: [NoGo] Some news messages would cause an assertion to be triggered due to a missing proper location for the viewport of the news message, so only allow building when valid data for the viewport is provided or no viewport is used [FS#5054] (r23924) +- Fix: Consider only the middle tile of a lock for lock-infrastructure costs. The other two tiles may be owned by other companies. Also do not count the middle tile of a lock as canal, independent of whether it is build on ground or river slope (r23920) +- Fix: [NewGRF] When determining the first refittable cargotype according to CTT order, do not rely on the GRF assigning the refit_mask property. Also check for GRFs setting the default_cargo or refittable-cargo-classes or -types properties (r23916) +- Fix: [NewGRF] Do not test validity of cargobits using a mask of cargoslots (r23914) +- Fix: [NewGRF] When testing whether a engine shall only carry the default cargo, check ctt_include_mask for being empty before applying cargo translation (r23912) +- Fix: [SDL] Handle the SDL_VIDEOEXPOSE event to solve issues with SDL 1.3 (r23910) +- Fix: [SDL] Fix keyboard-related segfault when compiling against SDL 1.3 (r23909) +- Fix: [Makefile] Make sure bin/baseset/openttd.32.bmp is removed on make clean (r23908) +- Fix: [Makefile] Let 'make clean --dry-run' not delete Makefiles (r23907) +- Fix: [Windows installer] OpenMSX got downloaded to and extracted in the wrong (non-existent) folder [FS#5045] (r23905) +- Fix: Memory leak every time one clicked a savegame in the load GUI (r23901) +- Fix: [NewGRF] It was not possible to import sounds from a NewGRF later in the load order (r23883) +- Remove: PNG sprite loader; use 32bpp sprites in a NewGRF (r23898) + + +1.2.0-beta4 (2012-02-04) +------------------------------------------------------------------------ +- Feature: [NewGRF] Give NewGRF defined level crossings and rail depots access to the townzone (r23866) +- Feature: [NewGRF] New algorithm (activated via an engine flag) to determine the capacity of vehicles. This allows vehicles to better control the capacity for cargotypes which they know; and let cargo NewGRFs influence the capacity for cargoes the vehicle NewGRF does not know, but which the vehicle is refittable to due to cargo classes (r23861) +- Feature: [NewGRF] Add cargo property 1D to set the capacity multipliers when refitting vehicles, which do not use callback 15 (r23860) +- Feature: Allow command line options -e and -g to be combined to load saves/scenarios directly into SE (r23839) +- Feature: [NoGo] Allow querying orders of vehicles [FS#4994] (r23837) +- Change: Do not let towns (ever) remove objects [FS#5001, FS#5002] (r23842) +- Change: Make signs placed in scenario editor belong to the GS. That way they are always shown in game and are not editable [FS#4999] (r23835) +- Fix: Generate industry subsidies again [FS#5039] (r23876) +- Fix: [NoGo/NoAI] Scripts with a bad comparator could lock up OpenTTD [FS#5004] (r23870) +- Fix: Make the colour of the dropdown items for opening the vehicle list for which the company has no vehicles looking less horrid [FS#5020] (r23867) +- Fix: Railtype overlays were drawn 'only transparent' on invisible bridges (r23864) +- Fix: Inserting conditional orders for ships checked the wrong orders wrt. maximum distance (r23859) +- Fix: Out of bounds read for slowdown parameter caused desync when railtype >= 4, vehicles were fast, and the original acceleration model was used [FS#5007] (r23855) +- Fix: Infrastructure cache could get out of sync when overbuilding a drive through road stop (r23851) +- Fix: When the network is lagging, you try to copy a vehicle's order but accidentally create a station order and then copy the vehicle's order (before the first command is executed) one could trigger an assertion from the pool [FS#5008] (r23849) +- Fix: When removing road or tram from a tram+road stop, the owner of the road stop's cache was updated instead of the owner of the removed infrastructure (r23847) +- Fix: Infrastructure count for stations was not updated properly on company takeover. And do not count buoys while loading a game either (r23844) +- Fix: Clear NewGRF vehicle cache when their owner changes (r23841) +- Fix: Assertion got hit when destroying a dock when a ship was loading [FS#5000] (r23838) +- Fix: If a vehicle is not refittable to any cargo in the CTT, then pick the first refittable cargoslot (r23836) + + +1.2.0-beta3 (2012-01-21) +------------------------------------------------------------------------ +- Feature: [NoGo] Allow to chose the goal question window's title from a (small) set of options [FS#4992] (r23827) +- Feature: [NewGRF] Enhance some fatal NewGRF errors with the sprite number that caused the problem (r23809) +- Fix: Loading empty GS strings/translations failed [FS#4996] (r23829) +- Fix: Return early from SlString() for empty strings, before doing invalid things which surprisingly do not break everything (r23828) +- Fix: The detailed performance rating window showed the cargo count of the current quarter instead of the last quarter like the tooltip says [FS#4972] (r23826) +- Fix: Removal of towns with 0 population failed during map generation [FS#4951] (r23819) +- Fix: [Network] Desync due to different NewGRF version at client and server [FS#4962] (r23817) +- Fix: [NewGRF] Textstack was not properly used when storing parameters for the error message window [FS#4969] (r23803) +- Fix: Game lobby GUI not updated when new company information becomes available [FS#4968] (r23802) +- Fix: Reading the UTF-8 BOM from AI/GS files on big-endian machines failed (r23801) +- Fix: Move 'refittable to' text above custom NewGRF text in build vehicle GUI [FS#4958] (r23792) +- Fix: [NewGRF] Resize text panel for parameter description if it does not fit in 4 lines [FS#4960] (r23791) +- Fix: [NewGRF] While we can only show one error per NewGRF, fatal errors should always disable the GRF. Also give those errors precedence over other information (r23789) +- Fix: [NewGRF] Failure to load NewGRF files that use action 0 general prop 15 with a missing language file (r23788) +- Fix: Crash due to genders used for station name in hangar string of Italian translation [FS#4965] (r23782) +- Fix: Under certain circumstances, e.g. a single invalid order, trying to determine the next order state could end up in an infinite loop [FS#4964] (r23781) +- Fix: [Network] Missing naming of some errors[FS#4963] (r23780) +- Fix: Trim all control codes and the likes from strings being passed into the AI. If the AI would be displaying them later we would be showing those control codes as question marks [FS#4957] (r23778) +- Fix: Hide the PCX screenshot format from the options window, if a 32bpp blitter is used (r23775) +- Fix: [NewGRF] Update all cached train properties if a train vehicle enters a new railtype (r23773) + + +1.2.0-beta2 (2012-01-07) +------------------------------------------------------------------------ +- Feature: [NewGRF] Allow read-only display of NewGRF parameters, if GRF list may not be edited (r23760) +- Feature: [NewGRF] Alternate rail type label list (r23758) +- Feature: Make the default secondary sort method for the server list the number of clients instead of the name (r23710) +- Feature: Try harder to sort text instead of fancy characters in the server names (r23709) +- Feature: Make a distinction between fully zoomed in and default zoomed in screenshots [FS#4916] (r23695) +- Feature: Add ability to adjust brightness of colour after remapping for 32bpp sprites (r23670) +- Feature: [GS] GSGoal::Question(), to ask a question to a(ll) company(ies). It can contain random text, and at most 3 buttons from a collection of 17 (r23731) +- Feature: Australian translation (r23730) +- Fix: Make default timeouts for certain network states lower and configurable [CVE-2012-0049] [FS#4955] (r23764) +- Fix: Check whether a water tile is really empty when overbuilding it with an object [FS#4956] (r23763) +- Fix: The check for duplicate town names was not really working [FS#4951] (r23759) +- Fix: Missing locking causing crash is extreme case when being in the MP lobby [FS#4938] (r23752) +- Fix: [Win32] Work around a possible deadlock when initialising threaded drawing (r23749) +- Fix: Make vehicle variables A8 and A9 always return 0. Returning cur_image is a potential desyncer due to Action1 in static NewGRFs (r23748) +- Fix: Also set 'info' to NULL if 'instance' dies (for both AI and GS); avoids invalid memory reads (r23746) +- Fix: If autorefit fails, count the vehicle capacity nevertheless, if it is already carrying the right thing (r23745) +- Fix: [NewGRF] Check the version of the right GRF [FS#4923] (r23744) +- Fix: [NewGRF] Call CB 15E for all vehicles before actually executing any refit [FS#4906] (r23743) +- Fix: Cheating to different climates messes things even more up than changing NewGRFs in-game so it was removed [FS#4939] (r23733) +- Fix: When cheating into another company, the SignList was not updated [FS#4942] (r23728) +- Fix: Reading memory of a temporary (already deconstructed) object is invalid (r23721) +- Fix: [Script] Show the script debug window also when the game script crashes [FS#4935] (r23720) +- Fix: Extraction of music packs failed [FS#4930] (r23719) +- Fix: [AI] Rescanai caused crash when the AI settings of an AI was opened [FS#4936] (r23718) +- Fix: Ships going to wrong dock location when moving the dock while the game is paused [FS#4927] (r23717) +- Fix: The amount of goals was too low [FS#4928] (r23699) +- Fix: Hardcode the original defaults for loading old savegames if they could totally mess with the game's behaviour [FS#4859] (r23693) +- Fix: Infrastructure count of canals/locks/ship depots was not updated properly when a company went into bankruptcy or was taken over [FS#4921] (r23686) +- Fix: When fitting another engine the cargo capacity of wagons could become lower, causing them to contain more than they should. This caused the cargo transfer from the replaced parts to put even more stuff in the already full wagon. Prevent this from happening by reducing the amount of cargo in the vehicle to the capacity when moving vehicles/wagons around, or when autoreplacing [FS#4912] (r23683) +- Fix: Vehicle numbers got miscounted when autoreplacing failed due to length checks [FS#4914] (r23681) +- Fix: [AI] Prevent removal of the (AI) company the local player is in [FS#4915] (r23680) +- Fix: [Script] Close the editbox of settings when changing an AI, to avoid invalid memory read/write (r23678) +- Fix: [Script] Invalidate AI Parameters window when changing AI [FS#4909] (r23677) +- Fix: When removing road stops the wrong tile was checked for updating the infrastructure cache [FS#4913] (r23676) +- Fix: [Script] The 'Configure' button in the 'AI / Game Configuration' window did not get enabled when activating a GameScript (r23668) + + +1.2.0-beta1 (2011-12-24) +------------------------------------------------------------------------ +- Feature: Ability to run a game script; a script that controls some of the logic of the game, e.g. to implement goals or tutorials (r23637) +- Feature: Allow to place locks also on river rapids and restore rivers, if locks are deleted [FS#4872] (r23512) +- Feature: Aircraft ranges (r23504) +- Feature: Configurable linewidth in plots (r23497, r22292) +- Feature: Add 'view website' button to the online content and NewGRF windows (r23495, r23492) +- Feature: [NewGRF] Action14 node INFO->URL_ to add an url (r23494) +- Feature: When looking for missing content, automatically select it so you can easily start the download [FS#4827] (r23468) +- Feature: Automatically close the online content window after confirming the download with 'ok' [FS#4827] (r23467) +- Feature: Add 'find missing content online' button to 'load savegame' and 'find network game' windows [FS#4827] (r23465) +- Feature: [NoAI] AIStation.GetStationCoverageRadius(StationID) (r23453) +- Feature: Infrastructure maintenance costs (r23415) +- Feature: Allow to create subsidies for any combination of source and destination types (r23408) +- Feature: Diagonal dragging the rail conversion tool when pressing CTRL [FS#4841] (r23338) +- Feature: Add ability to zoom in to 2x and 4x level (r23316) +- Feature: Settings to restrict viewport zoom levels (r23314) +- Feature: An economy.fund_buildingssetting, to disallow funding buildings (r23303) +- Feature: [NoAI] AITown::GetCargoGoal and AITown::GetGrowthRate to query statistics about a town regarding its growing (r23302) +- Feature: Show on the GUI when a town grows and what the requirements for growing are (r23300) +- Feature: [NewGRF] Properties to always include/exclude cargo types from the refit mask (r23291) +- Feature: A monospaced sprite font for the readme reader (r23288, r23274) +- Feature: Attempt to show a window for downloading the base graphics set if it is missing (r23244) +- Feature: In-game (translatable) readme.txt reader [FS#4780] (r23182, r23178) +- Feature: [NoAI] AICONFIG_AI_DEVELOPER flags to hide AI settings unless gui.ai_developer_tools is enabled (r23169) +- Feature: Always draw fences around field tiles [FS#1824] (r23168) +- Feature: Support for NewGRF version 8 (r23159) +- Feature: [NewGRF] Patch/setting variable 14: get the maximum height of the map (r23158) +- Feature: [NewGRF] Road vehicle property 23 to shorten vehicles without callback usage (r23149) +- Feature: [NewGRF] Allow passing 32bit parameters to 60+x variables (using var 7B). Currently most useful for vehicle var 60 (r23138) +- Feature: [NoAI] AICargoList_StationAccepting [FS#3799] (r23134) +- Feature: [NewGRF] Property for the rail type name (r23129) +- Feature: [NoAI] Allow AIs to query the amount of remaining operations for the current tick (r23118) +- Feature: [NewGRF] Ambient sound effect callback (r23114) +- Feature: Auto-refitting of vehicles during loading at a station when the vehicle allows it (r23089, r23087) +- Feature: [NewGRF] Callback to change refit cost depending on old and new cargo type (r23086) +- Feature: [NewGRF] Use variable 10 to enable vehicle GRFs to draw different sprites on the map and in various GUIs (r23080) +- Feature: [NewGRF] House callback 0x148 (r23072) +- Feature: [NewGRF] House variable 0x64 (r23070) +- Feature: [NewGRF] Long date of last service for vehicles, also available in the purchase list (r23068) +- Feature: A -q command line option to read a savegame, write some general info and exit (r23065) +- Feature: [NewGRF] stringcodes 9A 19 and 9A 20 to print 'short volume' and 'short weight' respectively (r23063) +- Feature: [NewGRF] Allow use of NewGRF text stack during callback 23 (r23040) +- Feature: Support company colour for the airports' runways [FS#4797] (r23010) +- Feature: [NewGRF] Allow to use offsets for all types of action5 except sea shores [FS#4795] (r23004) +- Feature: [NewGRF] Action2 variable 0x62 to get curvature/position difference to the n-th vehicle in vehicle chain [FS#2521] (r22998) +- Feature: [NewGRF] Allow access to other vehicles in the vehicle chain in VarAction 2 (r22997) +- Feature: Display autoreplace status in group GUI (r22985) +- Feature: Display profit icons for groups in the group GUI (r22984) +- Feature: Display the number of vehicles in the group GUI also for the ALL and DEFAULT groups (r22983) +- Feature: Allow road corners on steep slopes (r22968) +- Feature: Allow depots, standard road stops and airports on steep slopes (r22960) +- Feature: [NewGRF] Allow Action4 to change text IDs 0x00D1 to 0x00E0 for feature 48 (r22954) +- Feature: [NewGRF] Extended Action1 format to define arbitrary spriteset IDs (r22926) +- Feature: [NewGRF] Allow referencing spritesets from different Action1 in a single Action2 (r22925) +- Feature: Allow towns to build bridges over canals and rivers (r22899) +- Feature: Resize the tree build GUI to according to tree size (r22862) +- Feature: Conditional order depending on remaining lifetime of a vehicle (r22858) +- Feature: [NewGRF] Allow replacing depot sprites without having to provide rail overlays (r22854) +- Feature: Display separate ocean and canal speeds in the ship purchase list, if they differ (r22850) +- Feature: [NewGRF] Bits 8-31 in station variable 43 (r22848) +- Feature: [NewGRF] Also age wagons and articulated parts (r22816) +- Feature: [YAPF] Take canal/ocean speed fraction of ships into account (r22801) +- Feature: Progress bar for scanning NewGRFs (r22797) +- Feature: [NewGRF] Stringcodes for printing 0-based dates, unsigned words in power units (r22779, r22778) +- Feature: River generation (r22767) +- Feature: [NoAI] AITile::GetTownAuthority() (r22764) +- Feature: [NewGRF] Implement feature 04 property 18 bit 5 (r22746) +- Feature: [NewGRF] Per vehicle custom cargo ageing period (r22713) +- Feature: Display option to hide competitors' signs and station names [FS#4701] (r22708) +- Feature: Add a menu entry for the sprite bounding box debugging feature in the help menu and enable bounding boxes only in conjunction with the NewGRF developer tools (r22675) +- Feature: [NewGRF] Provide random bits in var 0x10 for callback 0x3B in all cases [FS#4690] (r22673) +- Feature: Do not spawn explosion effects when bulldozing in paused mode. They block the view (r22670) +- Feature: [NewGRF] Support for the land slope check callback for stations (r22659) +- Feature: [NewGRF] Custom error messages for object callback 0x157 (r22658) +- Feature: [NewGRF] More default error messages for the industry shape and location callbacks (r22657) +- Feature: [NewGRF] Add water class to the 'land info of nearby tiles' vars (r22655) +- Feature: [NewGRF] Support for ship props 14/15 (ocean/canal speed fraction) (r22639) +- Feature: [NoAI] Add several functions to AICompany to find out performance information (r22584) +- Feature: [NewGRF] Persistent storage for towns (r22569) +- Feature: [NewGRF] Support for station variable 0x69 (r22543) +- Feature: [NewGRF] Advanced sprite layouts with register modifiers (r22518) +- Feature: Save heightmap in scenario editor (r22514) +- Feature: Make the transparency options for industries also affect the effect vehicles created by industries [FS#4625] (r22506) +- Feature: [NewGRF] Implement variable 18 for custom station foundations (r22453) +- Feature: [NewGRF] When NewGRFs are disabled via Action E or due to GRM failure, also display an error in the GUI (r22444) +- Feature: [NewGRF] Allow to filter by town of the current industry when using industry variable 0x68 [FS#4591] (r22434) +- Feature: An advanced setting to specify the default palette to use for NewGRFs without action 14 palette information; this makes the default choice independent from the used base graphics (r22417) +- Feature: Sort the items in the currency dropdown; separate the 'Custom' item with a horizontal line from the rest (r22312) +- Feature: Separate default and NewGRF-supplied townnames with a horizontal line and only sort them within these groups (r22312) +- Feature: [NewGRF] Allow docks to feature company colour (r22293) +- Feature: Apply the same inflation to the initial loan as to the maximum loan. Note that this is no change to the economy; it only saves players some clicks when starting companies in later years (r22253) +- Feature: [NewGRF] Make var 0x48 available in CB 0x15C (r22231) +- Change: [Win32] Move painting the window and doing palette animation into a separate thread (r23482) +- Change: [SDL] Move 32bpp-anim palette animation to the draw thread instead of the single threaded bit of the game loop. This causes a speedup of up to 15% when animation is turned on with the 32bpp-anim blitter (r23451) +- Change: Make the company GUI somewhat smaller if there are no shareholders (r23424) +- Change: [NewGRF v8] Allow translating multiple languages with Action 13 (r23391) +- Change: Bring Squirrel to 2.2.5; besides some nice bug fixes, it mostly solves the sort() issues (r23383) +- Change: Move the 'default' overrides out of the base set in order to ensure they all use the same values (r23232) +- Change: Different directories for base sets and newgrfs. So data to base set or newgrf, and gm to base set (r23219) +- Change: [NewGRF v8] Do not override rail type prop 1B with prop 09 (r23166) +- Change: [NewGRF v8] Format of extra callback info for callback 144 (r23157) +- Change: [NewGRF v8] Use height level units in var 8A of callback 28 (r23155) +- Change: [NewGRF v8] Use height level units in nearby tile info variables (r23154) +- Change: [NewGRF v8] Use height level units in variable 20/A0 (r23153) +- Change: [NewGRF v8] Snow line height table uses values between 0x00 and 0xFF independent of number of height levels (r23152) +- Change: [NewGRF v8] Deprecate callback 11 and 12, and use callback 36 instead (r23151, r23150) +- Change: [NewGRF v8] Unify the return values of boolean callbacks, and check the results for validity (r23147) +- Change: [NewGRF v8] Make callback 22 return a probability to use instead of property 18 (r23146) +- Change: [NewGRF v8] Determine the 'first' refittable cargo of vehicles using the cargo ordering from the cargo translation table (r23145) +- Change: [NewGRF v8] Consider the 'default cargotype' properties as indices into the cargo translation table (r23144) +- Change: [NewGRF v8] Return the translated cargobit in vehicle var 42 (r23143) +- Change: [NewGRF v8] Unify the return values of callbacks returning D0xx texts (r23142) +- Change: [NewGRF v8] Invert result bit 10 of callbacks 149 and 157 to make them consistent with other slope check callbacks (r23141) +- Change: [NewGRF v8] Do no longer apply base cost fallbacks (r23139) +- Change: [NewGRF v8] New result format for callback 16 (r23137) +- Change: [NewGRF v8] Deprecate old-style callback results 0xFF?? (r23136) +- Change: Open the query string window centred as it (almost) always requires your attention [FS#4825] (r23130) +- Change: [NewGRF] Enforce that the default cargo type of a vehicle is one of the refittable cargoes in case of refittable engines (r23077) +- Change: Use the currency -> euro conversion rate for currencies that have been replaced with the euro, so when the switch happens the conversion rate at that point is roughly that of the real world conversion rate (r23056) +- Change: Disable palette animation for pixels with alpha, as the alpha and previous colour information will be lost when the palette is animated (r23016) +- Change: More suitable default news settings instead of everything on 'full' (r22897) +- Change: Always use the DOS palette for drawing, remove the '-i' option for palette selection (r22419) +- Change: Make YAPF the default pathfinder for ships, do not discourage players from using it anymore (r22352) +- Change: Remove pixel limiter for query strings (r22343) +- Fix: Dates cut off in the message history [FS#4896] (r23643) +- Fix: Fix transparency for steel mill, colour translations in some arctic buildings and a wrongly replaced sprites [FS#4892] (r23639) +- Fix: Draw PBS reservations also for bridges and tunnels with railtype overlays (r23586, r23584) +- Fix: Add missing characters for certain languages and the large font [FS#4870] (r23582) +- Fix: Extending a path reservation starting at a partially reserved rail station could fail [FS#4888] (r23564) +- Fix: [NoAI] ScriptSign::BuildSign() returned wrong result if the sign name was too long [FS#4886] (r23516) +- Fix: Drawing of newspaper headlines used different padding than the initial sizing of the window [FS#4884] (r23509) +- Fix: [Squirrel] Provide a proper error message when the _cmp meta-function does not return an integer (r23496) +- Fix: Make autoreplace, autorenew, cloning and autorefit check all articulated parts of a vehicle to find a shared cargo subtype (r23487) +- Fix: In case you already have orders, ignore the vehicles when adding an extra order [FS#4770] (r23484) +- Fix: Replace OS error messages with internal error messages when that is possible [FS#4594] (r23480) +- Fix: Clear the backed up orders of a removed station as well, otherwise one could create orders to a station that was never in the original backupped orders. For example a road vehicle trying to go to a buoy [FS#4876] (r23464) +- Fix: Do not assume all industries that cut trees have tile (0,0) and wait until all tiles of an industry are completed before starting to cut trees (r23458) +- Fix: Mark company window dirty when moving a rail engine creates or deletes a train (r23454) +- Fix: Some airport functions did not take the layout into account resulting in wrong noise levels or nearest towns [FS#4764] (r23441) +- Fix: Perform checks for NFORenum/GRFCodec in configure, including a version check so a proper error can be given when a too old GRFCodec or NFORenum is used [FS#4867] (r23438) +- Fix: Recolouring of some animated colours from the Windows (=least consistent) palette went wrong [FS#4868] (r23433) +- Fix: Prevent windows to be resized beyond the bounds of the (main) window [FS#4842] (r23429) +- Fix: [NoAI] The AIEvent.ET_COMPANY_NEW was only triggered if a company named itself, which seems like a very odd place to do so. Trigger it when the company is created instead (r23398) +- Fix: Bring some more order in the ordering of the windows, e.g. do not let a save or load dialogue get hidden by a news message [FS#4709] (r23336) +- Fix: Road vehicle purchase info failed to display vehicles carrying no cargo [FS#4820] (r23334) +- Fix: Abort building/moving HQ when clicking on the button again, just like when building rail, stations, etc [FS#4851] (r23331) +- Fix: Change the centre of train vehicles to depend on the vehicle length instead of being fixed at 4/8th of the original vehicle length to make sure shortened vehicles do not block tiles they should not block [FS#2379,FS#3569] (r23290) + + +1.1.5 (2012-01-14) +------------------------------------------------------------------------ +- Fix: Make default timeouts for certain network states lower and configurable [CVE-2012-0049] [FS#4955] (r23764) +- Fix: Check whether a water tile is really empty when overbuilding it with an object [FS#4956] (r23763) +- Fix: Missing locking causing crash in extreme case when being in the MP lobby [FS#4938] (r23752) +- Fix: Clear the backed up orders of a removed station as well, otherwise one could create orders to a station that was never in the original backupped orders. For example a road vehicle trying to go to a buoy [FS#4876] (r23464) +- Fix: Do not assume all industries that cut trees have tile (0,0) and wait until all tiles of an industry are completed before starting to cut trees (r23458) + + +1.1.4 (2011-12-05) +------------------------------------------------------------------------ +- Fix: Savegames made with the Catalan town name generator would trigger a 'savegame corrupt' exception [FS#4866] (r23418) +- Fix: [Network] Do not send chat messages to clients that have not joined yet [FS#4826] (r23337) +- Fix: Assertion could be triggered in case a station was removed just after a vehicle delivered cargo to it [FS#4849] (r23312) +- Fix: Pathfinders go haywire when you build a lock over a ship going perpendicular to the axis of the new lock [FS#4845] (r23284) +- Fix: [NewGRF] Prevent against writing data for unknown fonts (r23283) + + +1.1.4-RC1 (2011-11-20) +------------------------------------------------------------------------ +- Fix: 3-column view of NewGRF GUI had too much space for certain font sizes (r23251) +- Fix: Ignore special characters, such as the train 'character', when determining a fallback font (r23237) +- Fix: [NewGRF] Make train var 0xF3 consistent with TTDPatch (r23231) +- Fix: Invalidate build vehicle window when changing the setting for wagon speed limits (r23211) +- Fix: [NoAI] Hide AIObject from the documentation as it cannot be used (r23204, r23201) +- Fix: [Network] Unstable sorting in the network list when two servers had the exact same name [FS#4829] (r23202) +- Fix: Oil rigs that 'expired' did not get removed from the station list [FS#4822] (r23199) +- Fix: [Squirrel] replace custom qsort by std::sort to fix stack overflow [FS#4830] (r23190, r23187, r23186) +- Fix: Do not display railway fences between track and waypoints [FS#4627] (r23163) +- Fix: [NoAI] AIOrder did not handle implicit orders correctly in all cases [FS#4823] (r23135, r23133) +- Fix: When any keys on the on-screen keyboard were pressed the text cursor disappeared (r23132) +- Fix: [NoAI] AIOrder::IsCurrentOrderPartOfOrderList return false for valid vehicles and crashed for invalid ones (r23131) +- Fix: [NoAI] calling require() to include a file gave you 100.000 opcodes for free (r23117) +- Fix: Allow accessing the server's client info as well in the admin network [FS#4813] (r23115) +- Fix: [NewGRF] Run StartupEngines() if NewGRFs changed during loading a savegame, just like it is running when NewGRFs are changed during a game (r23083) +- Fix: Account for snow line table when determining the snow line for building houses (r23082) +- Fix: [NewGRF] If a NewGRF overrides a default house the minimum start year for that house was set to 1930 [FS#4794] (r23059) +- Fix: [NoAI] AIOrder::GetOrderCount() did not hide implicit orders (r23057) +- Fix: [NewGRF] When vehicles break down, update the image cache after changing the vehicle state (r23050) +- Fix: Use the same forest-check for the vegetation-map colour as for nearby station names [FS#4810] (r23049) +- Fix: Check that the selected font size is valid the font face in use and choose the nearest size to that selected if not. Font metrics should then just work (r23038) +- Fix: [NewGRF] Strip newlines from NewGRF strings that should not have newlines, e.g. the NewGRF's name [FS#4769] (r23036, r22970) +- Fix: The last custom playlist items went lost when the files in the .obm are not contiguous [FS#4776] (r23035, r23034, r23033) +- Fix: Palette conversion windows to DOS for light house / stadium animated colour was mixed up (r23032) +- Fix: For the admin 'bots' there was no distinction between bankruptcy and manual removal of companies even though the API suggested that [FS#4804] (r23031) +- Fix: Always show a chat message and send an admin packet when a new company is made [FS#4796] (r23030) +- Fix: Pass bottom of dropdown item rather than bottom of dropdown window, so the dropdown gets drawn better with different font sizes (r23018) +- Fix: AI backlog was to short to fully display the backtrace of some AI crashes [FS#4798] (r23012) +- Fix: When the last used server is deleted from the list also clear the last used server if it is the same [FS#4791] (r23011) +- Fix: [NewGRF] Make sure temporary storage is cleared before test and exec runs for DoCommands so NewGRF callbacks cannot change the result between the runs (r22996) +- Fix: [NewGRF] Tile was cleared before the object-placement callback was run, resulting in possible differences in test and exec run [FS#4775] (r22994) +- Fix: [NoAI] Do not return ERR_UNKNOWN when the vehicle would become too long (r22988) +- Fix: Draw buoy sprite without outline on the map, fix minor issues with original graphics (r22974, r22973, r22971, r22962) +- Fix: The savegame description and loading of savegames would crash with savegames from a patched stable (which did not bump the savegame version) [FS#4778] (r22958, r22957) +- Fix: Guard from reading outside the silly name list (r22955) +- Fix: [NewGRF] Properly limit the length of strings in a choice list (r22952) +- Fix: [NewGRF] Do not call CB 32 for disaster, effect vehicles or aircraft shadows/rotors (r22947) +- Fix: [NewGRF] Crash when accessing vehicle var 44 for a non-front aircraft [FS#4781] (r22946) +- Fix: Calculate the size of the start/stop vehicle button correctly (r22941) +- Fix: [OSX] Various OSX 10.7 issues causing OpenTTD to not work [FS#4751] (r22921, r22895, r22893, r22889) +- Fix: [NewGRF] Properties for feature 0x05 were not zeroed for each NewGRF, thus waterfeatures could glitch when the properties were set by a previous NewGRF and the NewGRF assumed the properties to be unmodified (r22918) +- Fix: Old TTO/TTD savegames could get non-stop via orders upon savegame loading, even when those orders did not exist back then. This 'conversion' feature is something for TTDPatch and old OpenTTD savegames [FS#4716] (r22914) +- Fix: The icon would (almost) never be shown for SDL builds [FS#4617] (r22910) +- Fix: The name of the heightmap glitches in the 'play heightmap' window (r22902) +- Fix: Locks would be incorrectly assembled (r22108) + + +1.1.3 (2011-09-15) +------------------------------------------------------------------------ +- Fix: Prevent authentication bypass for the admin port when a new game is started [FS#4771] (r22934) +- Fix: TTO savegames with any aircraft not in an hangar caused crashes during load (r22915) +- Fix: Windows 2000 and XP without service pack 3 must use the win9x binary/installer; the newer MSVC compiler of the compile farm does not support those versions of Windows anymore [FS#4749] (r22909) + + +1.1.3-RC1 (2011-09-04) +------------------------------------------------------------------------ +- Add: River graphics for the original base set (r22766) +- Fix: [NewGRF] DCxx text references via the text stack are not allowed, but caused crash [FS#4758] (r22882) +- Fix: Harden memory allocation (r22881, r22880, r22875) +- Fix: Miscalculation of train curve speed limits (r22879) +- Fix: Validate image dimensions before loading [CVE-2011-3343] [FS#4747] (r22878, r22877, r22874, r22873) +- Fix: Report an error in the news if autoreplace/renew fails due to the engine type being no longer available [FS#4712] (r22876) +- Fix: Perform stricter checks on RLE compressed BMP images [CVE-2011-3343] [FS#4746] (r22872, r22871) +- Fix: [NewGRF] Variables 40 and 81 of callback 18 are not the same as 80 (r22867) +- Fix: [NewGRF] Generic callbacks shall chain to the next GRF when the callback fails (r22866, r22865) +- Fix: Perform stricter checks on some commands [CVE-2011-3341] [FS#4745] (r22845) +- Fix: Harden savegame load against too many AI config settings [CVE-2011-3342] [FS#4748] (r22843) +- Fix: Compilation with GCC 4.7 (r22832, r22728, r22719) +- Fix: Allow to demolish aqueducts built in the scenario editor [FS#4741] (r22821) +- Fix: Towns expanding from the 'wrong' side of a tunnel or bridge [FS#4731] (r22810, r22809) +- Fix: [NewGRF] String codes for dates should use unsigned words, like old OpenTTD did before it learned dates before 1920 (r22774) +- Fix: [NoAI] Clarify the meaning of AIStation::IsWithinTownInfluence(), AITile::IsWithinTownInfluence() and AITown::IsWithinTownInfluence() [FS#4702] (r22763) +- Fix: [NewGRF] Also free allocated depot tables of NewGRF airports (r22760) +- Fix: [NewGRF] Invalid memory access when querying the grfID of the default objects [FS#4730] (r22757) +- Fix: When marking tile selections dirty, use the height information of the corners instead of the surface slope. This is more accurate when the foundation is kind of undefined [FS#4727] (r22755) +- Fix: Make aircraft point to the exit when leaving the hangar [FS#4696] (r22743, r22742, r22741) +- Fix: Display the size of the levelled platform in the measurement tooltip of terraforming operations [FS#4708] (r22740, r22739) +- Fix: Setting company passwords via the GUI on servers (including starting a company with the default password) failed, so no client could join that company [FS#4722] (r22738) +- Fix: [NewGRF] The construction stage sprites were incorrectly selected in cases other than 1 or 4 sprites per set (r22731) +- Fix: [NoAI] AITile::GetCargoAcceptance, AITile::GetCargoProduction and AIRail::BuildNewGRFRailStation did not check the cargo argument for validity (r22726) +- Fix: [NewGRF] Always draw NewGRF supplied texts with a default colour (r22725) +- Fix: [NewGRF] Do not restrict AdvVarAct2 to 255 operations (r22723) +- Fix: If there is no point in opening the rail/air toolbar, do not open it for people who use hotkeys either rather than only for those using GUI elements (r22716, r22715, r22714) +- Fix: [NoAI] Allow AIAirport::GetNoiseLevelIncrease() also for expired airports [FS#4704] (r22710) + + +1.1.2 (2011-08-14) +------------------------------------------------------------------------ +- Fix: Some corrupted savegames could crash OpenTTD instead of showing the 'savegame corrupted' message [CVE-2011-3342] [FS#4717] (r22737, r22736) +- Fix: [NewGRF] Triggering NOT_REACHED when playing with a NewGRF that supplies genders/cases for a language that was not installed [FS#4718] (r22735) + + +1.1.2-RC2 (2011-07-30) +------------------------------------------------------------------------ +- Fix: Cost of adding an extra road type to a bridge or tunnel was undercalculated [FS#4680, FS#4681] (r22700, r22699) +- Fix: Only insert cleared object tiles into _cleared_object_areas if clearing actually succeeds, else subsequent tests of the same tile will be skipped and considered successful [FS#4694] (r22698) +- Fix: When building a house it could be built at the wrong place if multitile houses failed some tests (r22697) +- Fix: [Network] Failed network address resolving could trigger temporary freezes [FS#4697] (r22696, r22695) +- Fix: [NewGRF] The override managers were not reset in some cases like creating a new scenario [FS#4691] (r22693) +- Fix: [NewGRF] Aircraft defined with IDs above the default aircraft's always defaulted to passenger cargo (r22690) + + +1.1.2-RC1 (2011-07-24) +------------------------------------------------------------------------ +- Change: [NewGRF] Only allow access (via hotkey and menu) to the bounding box visualisation when NewGRF developer tools are enabled (r22675) +- Fix: [NewGRF] Disallow accessing variable 1B in network games due to desync reasons (r22682) +- Fix: Switching from a red to a white highlight (by switching to another tool) without switching the highlight mode (HT_RECT etc.) did not mark the selection dirty [FS#4670] (r22649) +- Fix: [NewGRF] Parameters from NewGRFs were not properly parsed in all cases [FS#4599] (r22648, r22630, r22629, r22628, r22627) +- Fix: GetSection() does not return a LockPart [FS#4678] (r22645) +- Fix: [NewGRF] Disallow building NewObjects on water tiles owned by another company (r22643) +- Fix: [NewGRF] Disable the 'set parameters' button in the NewGRF GUI, if the GRF specifies to have no parameters and one would not be able to set any parameters anyway (r22642) +- Fix: Keep the previous owner of the upper and lower lock parts if they are built on existing water (r22638) +- Fix: [NewGRF] Airports should not expose the tile specific random bits of the north tile. Only airport tiles should access those (r22636) +- Fix: [NewGRF] Correctly reseed random bits of industries and industry tiles (r22635, r22634) +- Fix: [NewGRF] Implement variables 25 and 7F for railtypes (r22633) +- Fix: [NewGRF] Additional text in fund industry window is NewGRF supplied and thus should have a default colour (r22631) +- Fix: Also initialise _old_vds with newgame settings; TTD savegames do not contain these settings [FS#4622] (r22626) +- Fix: Do not zero the orders of disaster vehicles when converting savegames [FS#4642] (r22625) +- Fix: When closing an AI company the local player cheated to, we need to cheat him to another company [FS#4654] (r22624, r22623) +- Fix: When closing down companies their shares in other companies must be sold even if share trading is disabled at that point of time (r22622) +- Fix: When asking the user to confirm an unsafe unpausing, there is no need to execute a command if 'no' is chosen. This also prevents crashing when clicking unpause while the confirm window is shown (r22621) +- Fix: Enforce refit orders to be 'always go to depot' orders; service-only and stop-in-depot orders make no sense with refitting [FS#4651] (r22620) +- Fix: Consider the size of the vehicle sprite for the lineheight in the company GUI. This also makes the widget containing the sprite not skip drawing it, if the bounds of the widget are outside of the drawing area though the sprite actually needs drawing [FS#4662] (r22619) +- Fix: When changing difficulty settings over the network, do not just reopen the difficulty window if any game options window is opened; instead invalidate them properly [FS#4653] (r22618, r22617) +- Fix: [NewGRF] If callback 33 returns a value out of range, no sound effect shall be played [FS#4656] (r22614) +- Fix: Use rotated heightmap sizes for reporting scaling problems [FS#4663] (r22608) +- Fix: Do not show cargo accepted/produced in the new station window when no tiles are selected (mouse hovering a window or toolbar) [FS#4647] (r22595, r22593) +- Fix: Add active NewGRFs to the list of available ones when selecting the empty preset [FS#4644] (r22594) +- Fix: Reading of heightmaps with uncommon BMP formats failed due to uninitialised variables [FS#4645] (r22592) +- Fix: PBS order forecasting modified the current order index in case of a goto-nearest-depot order and no depot could be found [FS#4641] (r22589) +- Fix: Remove BaseStorageArrays from _changed_storage_arrays on destruction (r22583, r22551) +- Fix: Do not increment STL iterators after they have been invalidated (r22582) +- Fix: Do not lower the arrow buttons in the NewGRF/AI parameter windows if they are clicked when disabled (r22553, r22499) +- Fix: Clear airport persistent storage on construction/removal of airports (r22552) +- Fix: Possible crash when opening the airport build window for the first time [FS#4619] (r22538) +- Fix: Replace the half small airport structure on the intercontinental airport with some grass [FS#3494] (r22537) +- Fix: Documentation omission regarding admin protocol [FS#4632] (r22536) +- Fix: [NoAI] Doing rescan_ai in a game with running AIs caused a crash [FS#4631] (r22534) +- Fix: Do not create an implicit order if the current order is the first order in the order list and we visit the station of the last entry of the order list (r22532) +- Fix: MinGW 64 related compilation issues [FS#4623] (r22522, r22491, r22490, r22489) +- Fix: The layout selectors of the airport build GUI did not latch properly (r22497, r22495) +- Fix: Callback result for airport layout name was incorrectly used (r22496) +- Fix: Airport preview sprite can depend on the layout, so update the cached SpriteID when the layout changes (r22494) +- Fix: Engine IDs for coal and mail wagons were swapped in the TTO savegame conversion [FS#4622] (r22487) +- Fix: The caption of centred windows could be moved out of the main window and thus become inaccessible when resizing the main window (r22485, r22484) +- Fix: No client error packet was sent to the admin bots [FS#4585] (r22384) + + +1.1.1 (2011-06-01) +------------------------------------------------------------------------ +- Change: Automatic orders are better called implicit orders as no real order influencing path finding is added (r22474, r22473) +- Fix: Only try to insert implicit orders for ground vehicles. Aircraft may reach unscheduled terminals when skipping orders [FS#4624] (r22492) + + +1.1.1-RC1 (2011-05-15) +------------------------------------------------------------------------ +- Feature: [NewGRF] Allow to filter by town of the current industry when using industry variable 0x68 [FS#4591] (r22434) +- Change: Improve the speed of YAPF by tweaking hash tables size (r22351, r22350, r22348) +- Change: Show one digit of the fractional train length in the depot (r22336, r22305, r22304, r22303) +- Fix: When determining the executable path failed, the working directory was used instead, circumventing the not-home-directory check [FS#4613] (r22465) +- Fix: [Windows] Prevent a crash when launching OpenTTD with -d from a MSYS console [FS#4587] (r22464) +- Fix: Update the saveload window immediately after scanning a new directory, so queued events reach the window when already updated [FS#4615] (r22463) +- Fix: [NewGRF] The c and p parts of station vars 40, 41 and 49 were incorrect for large stations (r22455, r22286) +- Fix: [NewGRF] Zero register 0x100 as specified before resolving custom station foundations (r22452) +- Fix: Do not 'log' the NewGRFs in the screenshot when in the menu [FS#4610] (r22450) +- Fix: [NewGRF] When GRFs are disabled via Action E or due to GRM failure, also display an error in the GUI (r22444, r22443) +- Fix: [NewGRF] Do not popup fatal NewGRF error messages in the intro screen. The GRFs are not going to be activated there anyway and the GRF settings GUI will not display the errors either (r22442) +- Fix: Catenary was drawn incorrectly next to level crossings with foundations (r22437) +- Fix: [NewGRF] Apply railtype property 12 (station graphics) also to station groundsprites from action 1 (r22436) +- Fix: Git revision detection would return too much when tags are involved (r22435) +- Fix: [NewGRF] When action14 specified different values for the palette, the values were OR-ed. Use the last set value instead (r22416) +- Fix: [Network] Kicking yourself via remote console crashes the server [FS#4606] (r22414) +- Fix: [NewGRF] Make sure the action2 ID of a generic feature callback is valid (r22409) +- Fix: Check the availability year of all houses, not just the NewGRF houses, when making sure that at least one is available onwards from year 0 [FS#4581] (r22389, r22300, r22299) +- Fix: When a game uses a lot of NewGRFs the buffer for storing that information in the PNG is too small (r22388) +- Fix: Windows' recv seems to return 'graceful closed' before having passed the remaining buffer which causes OpenTTD to think all connections are 'incorrectly' terminated, i.e. without the 'I am leaving' packet from the client. So let the client wait a tiny bit after sending the 'I am leaving' packet and before gracefully closing the connection [FS#4601] (r22387) +- Fix: When the last AI company gets removed, the 'dead' state was not reset in the AI debug window [FS#4602] (r22386) +- Fix: Recolouring of silicon bridge was done incorrectly (r22380, r22379, r22378) +- Fix: Crash when clicking a removed company in the vehicle list dropdowns [FS#4592] (r22373) +- Fix: Keep better accounting of the order in which clients joined; client cannot be starved from joining and they get shown the amount of clients waiting in front of them (r22372, r22370, r22369, r22368, r22367, r22366, r22365, r22364, r22363, r22362, r22361) +- Fix: Make sure saving has completely and utterly finished before starting a new one. Otherwise you could start a save, which would be marked as done by the previous save stopping and then yet another save could be started... and that could create a deadlock [FS#4596] (r22371) +- Fix: Delete the client list popup when the client got removed (instead of previously selecting some other client) (r22360, r22359, r22358) +- Fix: When inserting automatic orders, do not create consecutive duplicate orders (r22333, r22332, r22331, r22330, r22329, r22328, r22327) +- Fix: Destinations of conditional orders were update incorrectly when deleting orders in front of the conditional orders, if the target order was the order just before of the conditional order (r22326) +- Fix: Vehicles skipped orders when inserting automatic orders failed (r22324) +- Fix: [NewGRF] When determining refittability use the cargo translation table of the GRF setting the refitmask instead of the GRF defining the action 3 (r22316) +- Fix: Make road vehicles, ships and aircraft skip orders if they are leaving a depot and heading to the same one again; just like trains (r22309) +- Fix: Waiting on a server could kick the client, or rather the client would kick itself due to an unexpected packet [FS#4574] (r22308) +- Fix: When drawing the town authority window, check whether the availability of the actions changed, and force a complete redraw in that case (r22307) +- Fix: The 'freeform edges' setting could be enabled when there were buoys on the northern border [FS#4580] (r22297) +- Fix: Reset Window::scrolling_scrollbar when raising scrollbar buttons [FS#4571] (r22294) + + +1.1.0 (2011-04-01) +------------------------------------------------------------------------ +- Fix: In the scenario editor you could build a ship depot using the appropriate hotkey. Removing that depot causes an assertion to trigger [FS#4558] (r22266) + + +1.1.0-RC3 (2011-03-18) +------------------------------------------------------------------------ +- Fix: New game settings were applied too early when starting a game via a heightmap [FS#4557] (r22259) +- Fix: Do not resort town, industry and signs list directly in OnInvalidateData(). There might be a scheduled rebuild which needs execution first. So, only set a trigger for resorting [FS#4546] (r22249, r22248, r22247, r22246, r22245, r22244, r22243, r22242, r22241, r22236, r22228, r22227, r22226) +- Fix: [NewGRF] Object variable 0x48 was not available in callback 0x15C (r22231) +- Fix: Compilation when compiling with --disable-ai (r22222) +- Fix: When downloading a file via HTTP failed mid-way and OpenTTD fell back to the old system the partial downloaded amount would be counted twice [FS#4543] (r22208) +- Fix: The 'center' (for movement) of vehicles is (currently still) always at 4/8th original vehicle length from the front, so trains should stop at the same location regardless of the length of the front engine [FS#4545] (r22206) +- Fix: Make the base costs for building and demolishing NewObjects also local to the individual NewGRFs (r22204) +- Fix: Removing a station order could stop when removing first automatic order (r22200) +- Fix: Invalidate the object build window when using the date cheat (r22193) + + +1.1.0-RC2 (2011-03-04) +------------------------------------------------------------------------ +- Fix: Following a vehicle with a very high VehicleID was impossible (r22181) +- Fix: [NewGRF] Memory leak if an industry NewGRF had more than one prop A or 15, or a station NewGRF had more than one prop 09 (r22175, r22165) +- Fix: [NewGRF] Disable a station NewGRF when it contains an unterminated spritelayout in action0 prop 08 instead of crashing (r22164) +- Fix: Building a station part adjacent to both an existing station and a rail waypoint failed [FS#4541] (r22163) +- Fix: No update of NewGRF window when unknown GRF name becomes available [FS#4533] (r22162) +- Fix: [NewGRF] Industry prop 0x11 is 4-bytes long, not 3 bytes (r22157) +- Fix: Stations/infrastructure were not properly sold on some clients during bankruptcy [FS#4529] (r22154) +- Fix: The Greek translation did not work as it breached the 200.000 bytes 'limit' for loading language files [FS#4536] (r22153) +- Fix: Windows video driver crashed when it could not go to full screen at the resolution of the configuration file when starting OpenTTD [FS#4521] (r22149) +- Fix: Do not run savegame conversion during SlNullPointers; the pointer might not be converted or be NULL at that point (r22146) +- Fix: Some valid keycodes were ignored along with the invalid ones (r22142) +- Fix: When commands need to invalidate windows, process these events asynchronously before the next redraw. Calling window code directly from command scope uses wrong _current_company and might issue nested DoCommands() which interfere with the running command [FS#4523] (r22141, r22140, r22135, r22134) +- Fix: [NewGRF] Skipping only the invalid part of an action14 failed, the rest of the action was skipped instead (r22138) +- Fix: Spectators had crashes when closing buoy windows (r22131) +- Fix: Build-station-window showed wrong selection when reopening [FS#4530] (r22128) +- Fix: Canals would get drawn as land in the smallmap when using the owner window (r22127) +- Fix: The animation-ness of two goldmine tiles were swapped, causing the wheeltower to not work properly, and the bottom corner to show the wrong sprite [FS#4528] (r22125) +- Fix: CommandQueue::Pop() did not update 'last'; popping the last item caused the queue to disconnect unless there was only one item [FS#4522] (r22123) +- Fix: When a NOT_REACHED in saveload can be reached due to an invalid savegame, use SlErrorCorrupt instead. In other words, do not crash but show an error message (r22122) +- Fix: In case of high frame_freq one could get commands executed after a new network game was started (r22121) +- Fix: [NoAI] Prevent AIs from getting consistently over their allowed amount of operations by subtracting the amount they went over 'budget' from the budget for the next 'tick' (r22120) +- Fix: The refit window was not correctly updated after selecting with Ctrl+Click [FS#4525] (r22118) +- Fix: CanRemoveRoadWithStop() failed for _current_company = OWNER_TOWN, and for OWNER_NONE-owned road (r22117) + + +1.1.0-RC1 (2011-02-18) +------------------------------------------------------------------------ +- Feature: [NewGRF] Test all possible industry layouts during construction and prospecting [FS#4131] (r22012, r22010) +- Feature: Wheel scrolling in the console (r21982) +- Feature: Console command to reset the engine pool. It removes the traces of engines which are no longer associated to a NewGRF, and can be used to e.g. 'fix' scenarios which were screwed up by the author. You can only use it when there are no vehicles in the game though (r21975) +- Feature: Add a setting to enable/disable funding local road reconstruction (r21974) +- Feature: Introduce 'minimal' number of industries as a replacement for the old 'none' setting in the new game window (r21969) +- Change: When loading old savegames with long trains set the maximum train length to the length of the longest train (r22061) +- Change: Always report mammoth trains are disabled to NewGRFs, and allow the maximum train length to be modified in multiplayer as well [FS#4471] (r22004) +- Fix: Remove invalid keycodes when reading hotkeys.cfg [FS#4510] (r22094) +- Fix: The server list did not get sorted with one item in it, so the 'position in the list' variable was never updated causing problems when using the keyboard shortcuts for scrolling [FS#4514] (r22093) +- Fix: When deleting towns, only relocate objects during DC_EXEC (r22087) +- Fix: [Windows] If fullscreen fails with current resolution, use desktop resolution [FS#4489] (r22081) +- Fix: The owner view of the smallmap was not updated after a company colour change (r22079) +- Fix: Maximum train length interfered with wagon replacement when wagon removal was turned on [FS#4499] (r22078) +- Fix: NewGRFs with invalid multi-tile houses could cause a valid 1x1 house following it to be seen as multi-tile, causing crashes [FS#4501] (r22075) +- Fix: Immediately update the train weight when you change the multiplier for train cargo weight (r22073) +- Fix: Some hotkey names in hotkey.cfg for the scenario editor toolbar were completely bogus (r22071) +- Fix: Crashes when disconnecting after requesting the map [FS#4503] (r22070) +- Fix: Delete all savegame packets, not just the first one (r22069) +- Fix: Return 'connection lost' instead of 'okay' when SendPackets closed the connection, so we do not try to do anything else with the closed socket (r22068) +- Fix: Do not hold a mutex when sending packets and thus possibly closing the connection as that wants to acquire the mutex again (r22067) +- Fix: Verify we can allocate an Order, OrderList, CargoPacket, CargoPayment, and others before we actually try to do so (all corner cases) [FS#4468] (r22066, r22057, r22047, r22042, r22040, r22033, r22031, r22026, r22025, r22024, r22023, r22022) +- Fix: Crash when disconnecting and reconnecting while the server is still saving the savegame [FS#4497] (r22064) +- Fix: Memory leak when saving with LZMA or zlib fails mid-way (r22062) +- Fix: Make the send chat message window follow the position of the status bar (r22059) +- Fix: Metric and imperial HP are not the same. As imperial HP are used internally, set a conversion rate for metric HP [FS#4408] (r22056) +- Fix: [Squirrel] Some invalid squirrel code caused the squirrel compiler to crash [FS#4490] (r22055) +- Fix: The land area information window was not updated after a language change (r22053) +- Fix: Roads under road stops would get a wrong owner after overbuilding (r22051) +- Fix: In ancient savegames, e.g. TTO savegames, non primary vehicles (wagons and such) could have unitnumbers or even orders. However, these orders would not be updated when a station is removed. As such some savegames have wagons with current orders to invalid stations which triggers trouble in the load conversion. So, trash any orders/unitnumbers a non-primary vehicle has [FS#4496] (r22050) +- Fix: [NewGRF] Company 0 does not always exist, so put temporary vehicles in a valid company (r22048) +- Fix: Make sure order indices stay in range when copying, sharing, unsharing or deleting all orders [FS#4487] (r22046) +- Fix: Update the consist cache when a part of a train is flipped in the depot [FS#4493] (r22044) +- Fix: Invalidate the right windows when a part of a train is flipped in the depot (r22043) +- Fix: Tab completion in chat did not cycle through all possible options (r22038) +- Fix: Crash when watching the vehicle view of a vehicle that has multiple sequential nearest depot orders (or consists of a single nearest depot order) when there is no depot with index 0 [FS#4488] (r22034) +- Fix: The server list got not resorted/redrawn after NewGRFs were downloaded [FS#4482] (r22029) +- Fix: When paused and having the allowed actions while paused setting on 'no actions' cheating money would fail [FS#4479] (r22016) +- Fix: Only show one AI per unique ID instead of all versions in the output of 'openttd -h' (r22007) +- Fix: Smoke/sparks of trains would be shown under bridges, or rather through bridges [FS#4480] (r22006) +- Fix: When the difference between force and resistance is smaller than the mass(*4) there would be no acceleration anymore, even when at higher (or lower) speed the force and resistance balance out better [FS#4473] (r21997) +- Fix: [YAPF] Under some circumstances vehicles could be lost [FS#4472] (r21996) +- Fix: [NewGRF] Make computations of closest-land/water-distances handle waterish tiles more correctly (r21994) +- Fix: When building a lock on dry land costs for clearing water were deducted rather than for building canals (r21993) +- Fix: AIs trying to change the AIOF_GOTO_NEAREST_DEPOT flag for existing orders triggered an assert. Explicitly forbid this as precondition for SetOrderFlags [FS#4467] (r21992) +- Fix: The share/copy-orders-cursor was not updated to refer to the new vehicle when it got autoreplaced/-renewed [FS#4466] (r21991) +- Fix: Vehicle status bar glitches on speed changes (r21989) +- Fix: Scrolling of the console in pages used wrong line height and scrolled too much (r21979) +- Fix: Redraw the town authority window after modifying town authority settings (r21973) +- Fix: Crash when a multiplayer company goes bankrupt with 'you' in it [FS#4464] (r21970) + + +1.1.0-beta5 (2011-02-04) +------------------------------------------------------------------------ +- Feature: GUI setting to disable reversing at signals (r21962) +- Feature: Not loading and not unloading is now possible (r21961) +- Change: [NewGRF] Disable the flipping of train engines/wagons in the depot by default for NewGRFs [FS#4462] (r21966) +- Change: Show the length of vehicles in tiles, instead of half tiles in the depot (r21960) +- Change: Replace longbridges settings with custom maximum bridge and tunnel length setting (r21959) +- Change: Randomise the vehicle a small UFO targets, do not use the one with lowest index (r21949) +- Fix: Do not count the number of vehicles but the length of vehicles to (configurably) limit train length [FS#4461] (r21960) +- Fix: [NewGRF] Reset the carry flag every 4 bytes in Action 6 when adding more than one variable (r21951) +- Fix: Road vehicle was moved under the bridge when it was destroyed by an UFO while on a bridge (r21948) +- Fix: Crash when converting a savegame with vehicles crashed in a tunnel entry, or with vehicles reversing there (r21947) +- Fix: Funny behaviour when a road vehicle reverses while overtaking, so abort the overtake attempt when reversing the road vehicle [FS#4447] (r21946) +- Fix: Not all vehicles should be tested to be inside a tunnel upon savegame load [FS#4460] (r21940) +- Fix: Do not remove existing road/tram bits when overbuilding stops of the opposite road type [FS#4457] (r21936) +- Fix: Allow to overbuild road stops which are built over trams (r21935) +- Fix: Automatic orders behave now stable wrt. service orders and are not added or removed depending on the need of servicing [FS#4440] (r21933) +- Fix: The town window would not be invalidated in the scenario editor if the ground changed and thus the required cargoes for town growth [FS#4554] (r21929) +- Fix: Converting an expensive rail type to a cheap one could give more money than removing and rebuilding cost (r21919) +- Fix: Languages improperly sorted in the 'start server' window [FS#4443] (r21918) +- Fix: The minimum speed needed for (realistic) acceleration to work properly can sometimes be more than the (temporary) maximum speed causing Clamp to 'fail'. Make sure that the minimum speed always overrules the maximum speed [FS#4442] (r21916) +- Fix: Include the capacity of non-refittable vehicles in the refitted-capacity, if their cargo matches (r21904) +- Fix: Do not count articulated parts when passing the number of vehicles to refit to the command. That may exceed 8 bits (r21902) +- Fix: [NoAI] Hide automatic orders from AIs as they have no way of dealing with them (r21900) +- Fix: Do not show a vehicle selection in the RefitWindow for refit orders. You cannot select anything anyway (r21899) +- Fix: Using a pointer-iterator and adding things (thus reallocating) to the iterated array caused OpenTTD to crash on invalid pointers [FS#4438] (r21898) +- Fix: Only some scenarios from the main scenario folder and no heightmaps could be started in the 'start server' window [FS#4421] (r21892) +- Fix: Crash when scrolling outside of the main window (with some video backends) [FS#4434] (r21889) +- Fix: [NewGRF] String codes 0x80 and 0x81 were broken since the typechecking of string parameters [FS#4422] (r21885) +- Fix: When a train after reversing ended at the last bit of a bridge ramp and directed outside the bridge, it could still have track set to TRACK_BIT_WORMHOLE (r21880) +- Fix: When a single-vehicle train was reversed while on a slope, its GOINGUP/DOWN were not swapped (r21874) +- Remove: Settings for vehicle speed in the vehicle view, long date in status bar, drawing of bridge pillars, support for depot orders, time tabling and joining of stations upon building (r21958, r21957, r21956, r21955, r21954) +- Remove: The non-uniform stations setting; it has been broken for over a year, and thus not used [FS#4456] (r21953) + + +1.1.0-beta4 (2011-01-21) +------------------------------------------------------------------------ +- Feature: [NewGRF] Rail type property to influence sorting of rail types in the drop down list [FS#4394] (r21866) +- Feature: [Network] Console command to change the password of other companies for servers [FS#4368] (r21855) +- Feature: [NewGRF] Introduction dates/required types for rail types; e.g. introduce a particular rail type in 1960 (or when a vehicle using it is introduced), but also allow limiting its introduction to only happen when the required railtypes are available [FS#4393] (r21842) +- Feature: Limit vehicle lateness to the length of a full timetable cycle, e.g. when a cycle takes 50 days and the vehicle is 65 days later reduce the lateness to 15 days (r21832) +- Feature: After building a road or tram bridge/tunnel, connect it to any existing road or tram (r21778, r21777) +- Feature: Display NewGRF object sprites during object picking (r21772) +- Feature: Display NewGRF station sprites during station picking (r21755) +- Change: Allow LMB scrolling with the mouse outside of the extra viewport instead of cancelling scrolling when going slightly over the edge (r21838) +- Change: Only show rail/road types that will eventually be available in-game. For example do not show trams when there is no tram NewGRF loaded (r21817) +- Change: Keep aqueducts and road/tram tunnels and bridges after removing a company (r21780) +- Fix: Distant-join station would build at the wrong location when having persistent building turned on and selecting a 'second' location for the station tile [FS#4430] (r21864) +- Fix: Slowing down of trains was done by reducing the speed by 10%, but also when you are just 1% too fast, so limit the slowdown till the new maximum speed [FS#4423] (r21847) +- Fix: Left-mouse-button dragging would switch over to other viewports instead of staying locked to the viewport you started on [FS#4419] (r21837) +- Fix: When a train was reversed while inside a tunnel/bridge, it would not have (re)set the GOINGUP/DOWN bits after leaving the tunnel/bridge (r21836) +- Fix: Desync debug savegames might not be actually saved in case threading is enabled, which is enabled by default [FS#4427] (r21833) +- Fix: Service orders for trains/aircraft would (sometimes) not get a time when autofilling [FS#4414] (r21831) +- Fix: Crash with the small map window on big endian platforms [FS#4417] (r21830) +- Fix: The expectations from the 'always build infrastructure' setting name/description did not match the behaviour [FS#4007] (r21826) +- Fix: Allow dragging of combo signals (again) [FS#4378] (r21816) +- Fix: [YAPF] Apply a pathfinder penalty for back of one-way path signals so those are not preferred over other possibilities [FS#3908] (r21815) +- Fix: Check GRF version from action 8, and disallow usage of GRFs with versions above 7 (r21814) +- Fix: Crash when displaying the owner view [FS#4411] (r21813) +- Fix: Do not create automatic orders when there are no manual orders, and remove unreached automatic orders when reaching an ordered waypoint or depot [FS#4404] (r21809, r21808) +- Fix: Loading a TTO savegame failed after loading a TTDP savegame (r21799, r21798) +- Fix: The size (in characters) of the string inputs was too small for loading some TTD savegames (r21797) +- Fix: Drive through road stop state was not properly converted from TTDPatch savegames [FS#4398] (r21796) +- Fix: Broken usage of GetTileOwner() caused wrong conversion of old savegames (r21793) +- Fix: Terraforming limit was off-by-one when terraforming a single tile height [FS#4407] (r21791) +- Fix: TTDPatch savegames can have train waypoints encoded as buoys [FS#4398] (r21790) +- Fix: When the font misses the fallback character '?', use the sprite font's '?' instead [FS#4405] (r21789) +- Fix: Crash due to invalid rail station width and height data stored in TTDPatch savegames [FS#4398] (r21786) +- Fix: Crash when converting savegame with custom waypoint name (r21784) +- Fix: Diagonal tile iterator failed for A * 0 selections [FS#4396] (r21768) +- Fix: Do not limit tile clearing during bankruptcy [FS#4397] (r21767) +- Fix: PBS reservation was not shown on road crossings with NewGRF railtypes [FS#4369] (r21765) +- Remove: The 'stopall' console command, as its functionality was broken. Group start/stop commands can be used instead [FS#4409] (r21804) + + +1.1.0-beta3 (2011-01-09) +------------------------------------------------------------------------ +- Feature: Configurable limit amount of tiles that can be cleared/terraformed by a company [FS#4331] (r21728) +- Feature: Show a list of companies in the owner legend and allow them to be toggled for visibility (r21720, r21718) +- Feature: Console command 'list_ai_libs' to get a list of recognised AI libraries [FS#4372] (r21703) +- Feature: Allow changing the AI configuration in the scenario editor / in game [FS#4362] (r21696) +- Change: Tune 'realistic' acceleration even more to make more trains reach their top speed, and make it behave more like TTDPatch (r21712) +- Change: Display the minimum height of the tile in the LandInfo window instead of the height of the northern corner. So it is more useful for NewGRF and AI developers, and maybe more transparent for players (r21711) +- Fix: The diagonal iterator would iterate twice over some tiles [FS#4395] (r21747) +- Fix: [NewGRF] Canal variable 83 accessed water random bits also for non-water tiles (e.g. watery industries or objects) (r21746) +- Fix: [NewGRF] Canal variable 80 shall return consistent heights within a lock (r21745) +- Fix: Allow Ctrl+Clicking automatic orders for scrolling to their destination (r21744) +- Fix: Coast tiles were not drawn under bridges [FS#4386] (r21743) +- Fix: Make clearing refit orders work again [FS#4388] (r21739) +- Fix: Start loading when cur_order_index points to the destination station, i.e. after deleting not-reached automatic orders [FS#4384] (r21738) +- Fix: A loading order was also marked as 'not part of orders' when the order before the current order was deleted (r21737) +- Fix: Admin bots were not always notified of password changes [FS#4377] (r21727) +- Fix: Vehicle sprite was cached into a 16 bit variable, causing incorrect sprites to be displayed (r21709) +- Fix: [NewGRF] Report TTDPatch flag 4A (newobjects) as set (r21708) +- Fix: The old ship pathfinder is too stupid to provide 'lost' notices; it would even get lost while following its own path [FS#4370] (r21706) +- Fix: Do not perform any more checks after the connection is closed [FS#4374] (r21704) +- Fix: Changing AI settings ingame was impossible when the difficulty level was other than custom (r21694) +- Fix: Due to an error in the Debian changelog building of Debian/Ubuntu packages failed (r21682) + + +1.1.0-beta2 (2010-12-31) +------------------------------------------------------------------------ +- Feature: Command logging using the admin interface (r21668) +- Feature: Concept of automatic station orders; add stub orders for intermediate stations and remove them when not visiting them anymore. This allows you to see what trains visit a station without actually having to order a vehicle to stop at all stations (r21642) +- Add: [NoAI] AIEventTownFounded (r21664) +- Add: [NoAI] AIRail::GetName() to get the name of a railtype (r21663) +- Add: [NoAI] AITown::IsCity() so AIs can find out which towns grow faster than others (r21654) +- Change: Do not show price to build a bridge in the scenario editor as they are free to build there [FS#4358] (r21673) +- Change: Do not highlight tile when selecting a vehicle to clone or an order to skip to (r21616) +- Fix: Estonia introduced the Euro in 2011 (r21670) +- Fix: Autofill timetable had side effects in test mode, possibly causing desyncs in MP [FS#4354] (r21660) +- Fix: Cargo payment graph was not properly invalidated when payment rate changed [FS#4351] (r21658) +- Fix: Use a bool instead of uint8 to store a bool and use the dedicated accessor function when reading boolean settings [FS#4345] (r21656) +- Fix: Infinite loop in the road pathfinder due to bouncing around in an 'one way' trap; two one ways pointing towards each other making it impossible to leave [FS#4338] (r21651) +- Fix: Make '[centre|main] view' consistent, and make '[main|global] view' consistent [FS#4339] (r21650) +- Fix: Newly created skip-to order was created at wrong place (r21633) +- Fix: Ships with the old pathfinder would easily show up as lost, even when it would eventually find a path. Now also the distance from the 'end' of the pathfinding run to the destination is compared to the current distance to the destination; if the distance to the destination at the end of the pathfinder run is less than the current distance from the destination the ship will not be marked as lost. This means that the ships with the old pathfinder will less likely get marked as lost, but due to the design of the old ship pathfinder there 'lostness' is merely a best guess. When you still get a lost message you need to build buoys to guide the ship pathfinder [FS#4325] (r21631) +- Fix: Version detection of subversion branches and tags got broken (r21630) +- Fix: Crash under certain circumstances when using autorail [FS#4327] (r21619) + + +1.1.0-beta1 (2010-12-24) +------------------------------------------------------------------------ +- Feature: [NewGRF] Variable 7B for accessing 60+x variables while taking the parameter from the accumulator (r21604) +- Feature: Allow to refit only the selected part of a train consist (r21567) +- Feature: Store the used OpenTTD version, base graphics set, NewGRFs and AIs in the PNG screenshots (r21558, r21553) +- Feature: Make the delay of the chat messages timing out unrelated to the number of passed game days, i.e. do not stop ageing chat messages when the server is paused, and make the timeout user configurable [FS#532] (r21513, r21512) +- Feature: Vehicle lost messages for ships and road vehicles [FS#1956] (r21511, r21510) +- Feature: Diagonal tile clearing and terraforming by pressing Ctrl [FS#730] (r21500) +- Feature: [NewGRF] Use the station graphics property to determine a fallback for the depot sprites [FS#4279] (r21473) +- Feature: Add explicit make 'shared orders' an option in the orders menu (r21464) +- Feature: Make it more clear that you are stopping a shared order, and make it possible retain the order list upon unsharing [FS#3711] (r21461) +- Feature: Hotkey Ctrl+W for returning to the main menu [FS#3217] (r21459) +- Feature: Scroll to the inserted order [FS#4215] (r21457) +- Feature: Building while paused always works in the scenario editor [FS#1521] (r21430) +- Feature: Perform the compression of savegames to send to the client asynchronously. This will reduce the lag of the other clients to the time it takes to make the memory dump and it will speed up downloading the map as the download starts earlier (possibly with a slightly lower bandwidth due to slow compression) [FS#4284] (r21399) +- Feature: Do not store savegames to disk when transferring it from the server to a client (r21398, r21397) +- Feature: Use alphabetical order when sorting industries by type at the industry directory window (r21389) +- Feature: Allow entering of the new year in a text box when cheating the year [FS#4289] (r21388) +- Feature: Support for limiting the amount of (accepted) incoming data for a server (r21363) +- Feature: Natural sorting of strings using ICU [FS#4214] (r21344) +- Feature: [NewGRF] Implement action0 visual effect properties for ships and RVs (r21240) +- Feature: [NewGRF] Support callback 0x10 for RVs and ships (r21238) +- Feature: [NewGRF] Make positioning of diesel fumes and electric sparks actually work (r21230) +- Feature: [NewGRF] Support OpenTTD's genders, cases and plurals (r21216, r21211, r21209) +- Feature: Display mail capacity when refitting an aircraft to passengers (r21214) +- Feature: Make the statusbar's location configurable [FS#4201] (r21179) +- Feature: Forced construction of missing industries (r21175) +- Feature: Do not build industries during economic recession (r21169) +- Feature: Use desired industry counts rather than relative probability to decide which industry to build (r21168) +- Feature: Allow to sort purchase lists for trains and road vehicles by tractive effort (r21105) +- Feature: [NewGRF] Add CB36 support for road vehicle property 0x15 (Speed) (r21100) +- Feature: [NewGRF] Implement stringcode 9A 0C (station name), 9A 0D (weight) (r21086, r21085) +- Feature: [NewGRF] Add CB36 support for road vehicle properties 0x13 (Power), 0x14 (Weight) and 0x18 (Tractive effort) (r21058) +- Feature: XZ/LZMA2 savegame support. New default reduces savegame size by 10 to 30% with slightly more CPU usage. With maximum settings it reduces savegame size by 20 to 30%, but that takes 7 to 14 times longer. Map saving + downloading takes, on average, 5% less (r21044) +- Feature: Chat directly to the server or a bot/admin/IRC channel monitoring the server (r21000) +- Feature: Remote administration (r20975-r20963) +- Feature: [NewGRF] The concept of minimum loadable version to NewGRFs when choosing compatible NewGRFs (r20960, r20958) +- Feature: Centre new extra viewports on the tile below the mouse. Only centre on centre of main viewport if mouse is not in any viewport (r20956) +- Feature: [NewGRF] Make it possible to distinguish player built/randomly placed industries in the location and land slope check callbacks (r20942) +- Feature: Highlight all destination tiles when building a lock [FS#4153] (r20932) +- Feature: Transfer orders imply 'leave empty' by default [FS#3905] (r20927) +- Feature: Allow to select a custom percentage of water in the map generation window (r20832) +- Feature: Make it possible to select vehicle to clone and vehicle to clone orders from directly from vehicle lists and depot window [FS#3999] (r20753) +- Feature: Separate GUI icons for vehicle/company profit, exclusive rights and unread news (r20720) +- Feature: [NewGRF] Support for newobjects (r20670) +- Feature: Make the (flat) area around an industry configurable (r20659) +- Feature: [Network] Allow rate limiting of incoming commands (r20553) +- Feature: Filter signs at the sign list window [FS#3472] (r20516) +- Feature: Ignore _ in console command names so there is no 'inconsistent' behaviour w.r.t. underscores anymore without breaking backward compatibility greatly (r20515) +- Feature: A new screenshot type that makes a zoomed-in screenshot of the visible viewport [FS#3973] (r20508) +- Feature: Setting for none/original/more smoke [FS#3093] (r20376) +- Feature: Airport previews (r20381, r20369) +- Feature: [NewGRF] Support for callback 0x147 ('add sprite offset') for canals (r20353) +- Feature: [NewGRF] Support for property 09, feature 05, i.e alternate canal sprite layout (r20352) +- Feature: Add rescan_newgrf console command (r20344) +- Feature: [NewGRF] AdvVarAct2 operators for SHL, SHR and SAR (r20332) +- Feature: [NewGRF] Air drag property support for trains and road vehicles. Air drag for vehicles with air drag not set or set to zero will use a default value depending on their max speed (r20303, r20302, r20301, r20300, r20299) +- Feature: More user-friendly gui to change NewGRF parameters (r20258) +- Feature: [NewGRF] Add support for static NewGRF information, i.e. Action 14 (r20250) +- Feature: Display suppliers and customers of an industry or cargo (r20206) +- Feature: Allow horizontal resizing for all vehicle lists [FS#3955] (r20174) +- Feature: [NewGRF] Information (var 4A) about the current railtype a train is on (r20165) +- Feature: Tooltips are shown by hovering the mouse over a widget instead of by right clicking on it [FS#3913] +- Feature: Customisable hotkeys (r20055) +- Feature: Wrap console lines when they are too long [FS#3816] (r20046) +- Feature: [NewGRF] Variable 43 depot build date for railtypes [FS#3886] (r20003) +- Feature: Show some savegame details when selecting items in saveload GUIs (r19984) +- Feature: Open vehicle view when clicking on the caption of vehicle news (r19944) +- Feature: [NewGRF] Access to industry founder (var A7) during callbacks 28 and 2F (r19901) +- Feature: Add highlighting of drag destination in depot and order GUI gui [FS#3705] (r19889, r19888) +- Feature: Configure NewGRFs from a single window (r19841) +- Feature: Give depots an unique name in the same manner buoys and waypoints are named. Also allow them to be custom named [FS#3691] (r19801, r19799) +- Feature: Hide all other industries when Ctrl+clicking an industry type in smallmap legend (r19770) +- Feature: [NewGRF] Access to random bits of houses and industries from construction callbacks 17, 28 and 2F. That is: The random bits the house/industry will start with, if construction succeeds [FS#3477] (r19744) +- Feature: A simple sprite alignment helper. It does not store the new offsets anywhere so as soon as the sprite is reloaded the offsets are gone (use a bigger sprite cache if this happens). Also anything that reloads NewGRFs (new games, loading games or (re)applying NewGRFs) clears the sprite cache and as such resets the offsets (r19723) +- Feature: New base costs for building/clearing canals, building/clearing aqueducts and building/clearing locks (r19720) +- Feature: Ctrl+click on a vehicle to start/stop it (r19714) +- Feature: NewGRF debugging/inspecting of (primarily) enabled callbacks and values of variables (r19709) +- Feature: Graphs with negative values are no longer forced to have the zero axis in the middle, resizeable graphs (r19662, r19631) +- Feature: [NewGRF] Support callback 36 for aircraft speed also in the build menu (r19660) +- Feature: Add an input box to the AI Debug window where you can input a break string [FS#3496] (r19544) +- Feature: Add buttons to enable/disable all cargoes at the cargo payment rates graph (r19542) +- Feature: Sort industries alphabetically at the smallmap legend, fund industry list; sort cargoes alphabetically at cargo payment graph, build vehicles cargo filter dropdown, station ratings and refit options (r19541, r19540, r19436, r19535, r19522, r19503) +- Feature: Console command 'reload_newgrfs'; only available when NewGRF developer tools are enabled (r19515) +- Feature: Enter the starting year in the scenario editor by clicking at the date panel (r19397) +- Feature: Configurable slope steepness for road vehicles from 0% to 10%, default is 7% (r19346) +- Feature: Realistic acceleration for road vehicles (r19345) +- Feature: Allow to (over)build and remove multiple road stops using drag and drop (r19231, r19230, r19229) +- Feature: Show warnings and errors in console as well, not only in a message box (r19225) +- Feature: [NewGRF] Action 0/1/2/3 support for NewGRF airporttiles (r19194) +- Add: [NoAI] AIOrder::IsVoidOrder to find void '(Invalid Order)' orders (r20389) +- Add: Support for MSVC 2010 (r20032) +- Add: [NoAI] AIIndustry::GetIndustryID(TileIndex) (r19773) +- Change: Make it possible to start actions that require selecting stuff (landscaping, vehicle cloning, etc) in the viewport while paused. As side-effect you will get an error message explaining the command cannot be executed because the game is paused instead of seemingly nothing happening when you click. Additional side effect of this is that you can make use of the measurement tooltip while paused [FS#4292] (r21480) +- Change: Make building aqueducts behave more like building tunnels. They cannot be built on flat (or foundation) tiles, so there is at most one destination tile like there is only one for tunnels [FS#4153] (r21471) +- Change: Place the bridge building window under the mouse instead of somewhere randomly on the screen and change the default sort order [FS#3975] (r21460) +- Change: Make sure the client is listening, or rather receiving, our frames (r21361) +- Change: Read some metadata from (official) source tarballs so you will more likely get the right version/revision out-of-the-box (r21351) +- Change: Be more explicit that the game state can get broken by changing NewGRFs (r21335) +- Change: Use the last red instead of last red exit penalty for making sure other waypoint entries are evaluated as well when they are occupied, e.g. when there are no signals before the waypoint but a train just beyond the waypoint is stopped (like for stations) (r21271) +- Change: Do not receive money for removing the rail of non-rail rail station tiles, i.e. rail station tiles for which the NewGRF has prevented trains to be routed through (r21266) +- Change: Show a different 'lag' message when a client is lagging because of connection trouble or lagging because the client is just slow (r21254) +- Change: Mention the OpenTTD version on the console/logs when starting an OpenTTD dedicated server like we mention it in the title bar for the GUI version (r21253) +- Change: Filter stations by cargo they have a rating for instead of having cargo waiting [FS#4206] (r21144) +- Change: Limit the number of exceptions in the refittable cargo list to 7 (r21083) +- Change: Reduce the chances to accidentally break savegames with NewGRFs by limiting loading of savegames that miss NewGRFs or change NewGRF settings in-game [FS#3012] (r21116) +- Change: Tuned realistic acceleration to be a bit more realistic in order to make acceleration 'slower', which highlights the differences between vehicle types more (r21106) +- Change: Do not make client reconnect waiting time depend on the company; in coop games that does not spread clients at all, and most companies have a low number causing it not to be spread out either. Use the ClientID instead (r21008) +- Change: Add installing options or rather options to not install certain documentation, in a similar way to GRFCodec/catcodec (r20999) +- Change: Only display liveries in the livery window if they are used by some vehicle somewhen (r20849) +- Change: [NoAI] Rename AIAbstractList to AIList (r20563) +- Change: [NoAI] AIOrder::GetOrderFlags returns AIOrder::AIOF_INVALID for void orders (r20389) +- Change: [NewGRF] Adapt vehicle var FE bit 6 to new railtypes (r20175) +- Change: [NewGRF] Call callbacks 14A, 14B and 14C after all industry variables have been assigned, so more variables are valid during the callbacks (r19907) +- Change: [NoAI] Remove HasNext() from all lists/iterators and add IsEnd() instead (r19294) +- Change: Add the default installation directory of lzo/zlib for Mac OS X/MinGW to the paths where (the headers of) those libraries are searched [FS#3638] (r19285) +- Fix: Crash due to cargo payments belonging to a non-existing company [FS#4324] (r21605) +- Fix: Company league table used stats from two quarters ago instead of last quarter [FS#4323] (r21601) +- Fix: The default visual effect only depends on properties of the Engine (wagon or not, tractiontype, ...), not whether it is used as articulated part, front engine or whatever in a specific consist [FS#4275] (r21598) +- Fix: [OSX] A double mouse cursor was shown under certain circumstances [FS#2585] (r21578) +- Fix: Show 'plant trees' button lowered on the terraform toolbar, like how other buttons are lowered when you selected a 'build' action [FS#4315] (r21539) +- Fix: 2CC recolour sprites were the same for DOS and WIN palette, thus 'dark green', 'brown', 'grey' and 'white' were wrong for DOS [FS#4312] (r21535) +- Fix: Do not apply the last signal red pathfinder penalty when the signal is a path signal [FS#4302] (r21524) +- Fix: Tooltips were not removed when their related window got closed [FS#4300] (r21477) +- Fix: Make sure the query window is only opened once per parent window/callback [FS#4298] (r21472) +- Fix: Crash when news item gets removed at just the wrong moment [FS#4180] (r21458) +- Fix: [NewGRF] Ensure the parameter for house variable 60 is the id of an original house (r21456) +- Fix: [NewGRF] A NewGRF with incomplete string codes at the end of a string could cause invalid memory reads (r21433) +- Fix: The server did not check for the paused state when allowing to execute commands [FS#3771] (r21429) +- Fix: Vehicles could be built while the game is paused. Now you can enable or disable that with a setting, which replaces the build-while-paused cheat [FS#4021] (r21428) +- Fix: Purchase lists were not invalidated when using 'resetengines' (r21374) +- Fix: Fields were not cleared under snow though they were intended to be [FS#4283] (r21367) +- Fix: New railtypes with overlays did not use the shore sprites as groundtiles for three-corner-raised slopes (at shore) [FS#4277] (r21353) +- Fix: Buffer overflow in strgen for strings with very large arguments (r21346) +- Fix: Bogus cache mismatch warnings with desync debugging because some cache was invalidated but never reset [FS#4272] (r21338) +- Fix: Make it more likely that the savegame and transferred file are the same file and not different ones [FS#4271] (r21334) +- Fix: Use the correct font sizes when checking for missing glyphs (r21321) +- Fix: [Content] Crash when creating file download by the content download system failed (r21319) +- Fix: AIs in an infinite loop in e.g. autosave, but also getting settings and such from info.nut, would not be interrupted after a while causing OpenTTD to seem to not respond [FS#4260] (r21311) +- Fix: [Content] Do not add HTTP connection to list of connections when it fails in the beginning (r21302) +- Fix: Fonts set in openttd.cfg were not properly checked for missing glyphs on language change [FS#4261] (r21298) +- Fix: FreeBSD introduced strndup as well [FS#4259] (r21295) +- Fix: [Windows installer] Check for existence of save/scenario dirs before asking for deletion confirmation [FS#4251] (r21294) +- Fix: Under some circumstances two vehicles could leave a non drive-through road stop at once [FS#3935] (r21263) +- Fix: [NewGRF] Custom station foundations using the 'simple foundations'-method did not draw any sprite for WSE-slopes when there are foundations on both neighboured tiles in the north. As there must be at least one sprite to provide the correct offset for the groundsprite draw the (empty) default foundation sprite in that case [FS#4246] (r21262) +- Fix: The main menu error messages would not show when you had an error message open in the game while whatever triggered you to go back to the main menu (r21255) +- Fix: Rescanning AIs did not 'forget' removed AIs [FS#3952] (r21250) +- Fix: Upon rescanning AIs the new AIs would (after some time) show up in the AI list but you could not select all (r21246) +- Fix: [YAPF] Road vehicles not finding the nearest depot in some (corner) cases [FS#4130] (r21229) +- Fix: [NewGRF] The specs' cargo strings and OpenTTD's use of the clashed. Provide properties so NewGRFs can provide cargo strings tailored for OpenTTD while retaining (some) backward compatibility [FS#4172] (r21224) +- Fix: Use proper plural for the short cargo unit names (r21223) +- Fix: Under some conditions, group count would be wrong after moving train engines in the depot window [FS#4207] (r21205) +- Fix: [OSX] Do not let the mouse cursor jump when switching to full screen mode (r21200) +- Fix: [OSX] Finding a fallback font failed when compiling for OSX 10.4 as it tried to match also OpenTTD-specific control characters [FS#4001] (r21197) +- Fix: Use non-interactive randomness for townnames on map generation, so they are controlled by the generation seed as well [FS#4226] (r21192) +- Fix: [OSX] Unify compiler flags with other OS and work around a compiler bug in gcc-4.0.1 which breaks graphics display in x86_64 binaries [FS#4210] (r21149) +- Fix: Station list was not updated when a new cargo got a rating (r21145) +- Fix: Station ratings were not updated (anymore) after an aircraft crashed (r21137) +- Fix: Bridge speed limits should apply to all wagons of a vehicle, not just the head of the vehicle [FS#4213] (r21136) +- Fix: Helicopter flight altitude was determined inconsistently in different places (r21119) +- Fix: Do not use the maximum track speed where the maximum vehicle speed is meant (r21107) +- Fix: Display the real maximum speed for aircraft instead of always using the engine value (r21096) +- Fix: Aircraft speed would ignore callback 36 result when it is greater than the engine speed (r21094) +- Fix: [OSX] Mouse cursor would leave footprint with 8bpp blitter when switching to full screen (r21037) +- Fix: [OSX] Properly set the palette when using the 8bpp blitter during start-up (r21036) +- Fix: Centre industry gui and waypoint gui after resize [FS#4171] (r21021) +- Fix: Draw bridge pillars with correct length on all tile corners by drawing only half of the pillar sprite if required (r20950, r20947) +- Fix: Accidentally moving the mouse of the scrollbar arrows while pressing it clicks the button next to the arrow [FS#4071] (r20922) +- Fix: Refit costs were not shown for long cargo names [FS#4160] (r20921) +- Fix: When using non-smooth or NewGRF-economy changing production rates does not work, so allow changing the production multiplier instead (r20901) +- Fix: The station with the second highest rating was doubly penalised when distributing cargo. Now the penalty is completely removed and the granularity/precision of the distribution in increased by using fractional cargo. This should make competing stations less all-or-nothing [FS#3637] (r20857) +- Fix: Make sure (gradual) loading is properly terminated for consists with multiple cargo types. Do not stop loading if the timetabled wait is not over yet [FS#2534] (r20843) +- Fix: Place less trees at once when planting random trees at the scenario editor [FS#4094] (r20829) +- Fix: Do not use new game settings when creating many random towns/industries at the scenario editor [FS#4094] (r20712, r20711) +- Fix: Keep _current_company and _local_company in sync during GUI operation [FS#3804] (r19933) +- Fix: When building a lock, do not add the cost of building canals if they are already built, pay for clearing the other tiles and do not add the first bridge type's cost to aqueducts (r19719, r19718, r19717) + + +1.0.5 (2010-11-20) +------------------------------------------------------------------------ +(None) + + +1.0.5-RC2 (2010-11-14) +------------------------------------------------------------------------ +- Fix: Reading (very) recently freed memory [CVE-2010-4168] (r21182) +- Fix: Default service interval for ships/aircraft got switched [FS#4222] (r21155) +- Fix: Size of sort buttons for save/load and build vehicle list gui could be too small [FS#4221] (r21151) +- Fix: [Windows] Make sure to be upgraded openttd is not running when installing [FS#4212] (r21146) +- Fix: [NewGRF] Crash when disabling static NewGRFs (when joining/starting a server) [FS#4208] (r21130, r21129, r21128) +- Fix: Upper limit for snowline was too low [FS#4203] (r21078) +- Fix: Wrong (maximum) value shown for generation seed in the in-game console [FS#4192] (r21075) +- Fix: Under some circumstances the file handle of the downloaded savegame would not be closed, and validity of the handled was not checked in all cases (r21027) +- Fix: [NewGRF] Crash when getting an industry ID at an offset that uses some 'old' style industry tile [FS#4157] (r20912) + + +1.0.5-RC1 (2010-10-31) +------------------------------------------------------------------------ +- Change: Make OpenTTD aware of XZ/LZMA compressed savegames so loading those gives a proper error message (r21047) +- Change: Make it possible to make .tar.xz bundles (r21042) +- Fix: Missing default values for the custom town number in the world generation options (r21034) +- Fix: Dropdown menu glitched in small screenshots, when issuing them from the menu (r21031) +- Fix: Do not let the resize button go past the bottom of the screen [FS#4176] (r21015) +- Fix: The detailed performance rating window could be too narrow [FS#4102] (r21010) +- Fix: For the compact notation 1.000.000k and 1.000M would be shown depending on the initial (and later rounded) value. Make everything that would round to 1.000.000k be drawn as 1.000M as well (r21009) +- Fix: Do not consider the text direction character when searching for missing glyphs (r21007) +- Fix: Chat/console messages got sometimes messed up due to LTR names in RTL translations and vice-versa [FS#3746] (r21006, r21004) +- Fix: Size of sort buttons for order and vehicle list gui could be too small (r20997) +- Fix: [NewGRF] The X and Y offsets in the parameter for industry vars 60, 61, 62, 63 are unsigned instead of signed (r20996) +- Fix: When removing a rail station, do not leave track under non-station tiles (r20990) +- Fix: [NewGRF] Ignore the variable for Action7/9 condition type 0x0D and 0x0E as documented (r20979) +- Fix: Crash when, while the 'go to' cursor is active, you open the order list of a vehicle of another company and then select a 'go to' destination [FS#4159] (r20916) +- Fix: Helicopters fired a bit too late [FS#4155] (r20910) +- Fix: Road/water toolbars did not get updated when the first vehicle of their type becomes available [FS#4141] (r20856) +- Fix: Smallmap legend buttons must all be equal in size, even if their contents is not (r20851) +- Fix: Deadlock when aborting map generation on Windows [FS#3707] (r20822) +- Fix: Be a bit more lenient with invalid savegames; do not crash on saveload related NOT_REACHEDs, just show the user an error that the savegame is corrupted [FS#3714] (r20819) +- Fix: Make the crash-on-saveload message clearer and more correct [FS#3791] (r20818) +- Fix: [NewGRF] Clamp/convert some vehicle variables so NewGRFs get their specified range (r20800, r20799, r20792) +- Fix: [NoAI] Document that AITile::HasTransportType does not work for TRANSPORT_AIR [FS#4117] (r20798) +- Fix: [NewGRF] Disable houses without a size that are available according to their building flags (r20797) +- Fix: [NewGRF] Make sure all houses in the house spec array are valid. It was possible that part of a multitile house was not copied because the array was full (r20796) +- Fix: Building 2x2 houses did not work for 2x2 road layouts on all map sizes (r20791) +- Fix: [NewGRF] Remove a check which is wrong for NewGRF houses and serves no use for original houses [FS#4118] (r20790) +- Fix: Spelling mistake in Slovak real town names (r20787) +- Fix: Do autosave-on-exit as well when using kill/CTRL-C to terminate a dedicated OpenTTD (r20783) +- Fix: [NoAI] AIEventCompanyAskMerger was disguised as AIEventCompanyMerger (r20765) +- Fix: [NewGRF] Assert when an industry previously build on water was flooded because its NewGRF changed/is missing [FS#4112] (r20754) +- Fix: Do not use new game settings when creating many random towns/industries in the scenario editor [FS#4094] (r20712, r20711) +- Fix: Graphics glitch when switching to a different-sized font while the chat message box was visible (r20705) +- Fix: Vehicle lists of non-trains could not resize horizontally causing truncation of texts [FS#4123, FS#3955] (r20174) + + +1.0.4 (2010-09-14) +------------------------------------------------------------------------ +- Change: Move removal of bin/data/opentt[dw].grf from distclean to maintainer-clean (r20752) +- Fix: Recent NFORenum does not know '-?' (r20715) + + +1.0.4-RC1 (2010-08-30) +------------------------------------------------------------------------ +- Change: Merge the extra GRF's sources and make it possible to rebuild them easily (r20490) +- Fix: Empty NewGRF presets were not selectable [FS#4087] (r20694) +- Fix: Desync checker checked the wrong variable (r20677) +- Fix: Drawing the 'OpenTTD' text in the intro game caused crashes with very low resolutions [FS#4081] (r20618) +- Fix: Crash when a NewGRF defined an invalid substitute type for a house and the NewGRF was removed during the game, disable houses with different size than their substitute [FS#3702] (r20611, r20610, r20609) +- Fix: Retain information about all base sets that are found and not only the latest version to stop confusing people that use newer versions of the base sets than those available via BaNaNaS (r20607) +- Fix: Let NewGRFs var43 var (information about liveries) for vehicles not be influenced by the local setting determining whether to show liveries or not [FS#4063] (r20605) +- Fix: 'Downscale' a full load order to a load if possible order when removing the order while the vehicle is loading. This to prevent the vehicle from (possibly) staying forever in the station [FS#4075] (r20600) +- Fix: Crash when the tooltip is wider than the window is [FS#4066] (r20596) +- Fix: No (proper) savegame conversion was done when _date_fract got a new value range (r20592) +- Fix: Autoreplace failed while attaching non-replaced wagons to the new chain, if to-be-sold-engines would become front-engines and the unitnumber limit would be exceeded (r20583) +- Fix: Autoreplace can trigger an assertion when at the vehicle limit [FS#4044] (r20582) +- Fix: Go via station and go via waypoint behaved differently when a train went back to the same (unordered) station again [FS#4039] (r20580) +- Fix: Draw bounding boxes using white instead of pure white, so they are recoloured to grey in coloured newspaper instead of blue [FS#4051] (r20578) +- Fix: Scroll button flickering when pressed [FS#4043] (r20577) +- Fix: Warn OpenGFX users when they are using a base set that misses sprites (r20566) +- Fix: Wrong tooltip for the company select button in the AI debug and performance rating windows [FS#4053] (r20556, r20555) +- Fix: In old savegames aircraft can have an invalid state (r20528) +- Fix: Crash when the content download tried to get a MD5 checksum of an 'originally' loaded NewGRF [FS#4038] (r20519) +- Fix: Draw error messages in white by default, they may not have a colour set when coming from a NewGRF (r20514) +- Fix: Entering half the 'generation seeds' in the console's 'newgame' command failed to set the correct seed [FS#4036] (r20512) +- Fix: Desync when vehicles change NewGRF properties such as visual effect when changing railtype [FS#3978] (r20505, r20504, r20503, r20502) +- Fix: Desync when converting rail all as trains with a part on the converted rails need updating and not only the engines (r20500) +- Fix: Ignore the non-stop state when comparing one order type to another order type, otherwise non-stop nearest depot orders fail [FS#4030] (r20498) +- Fix: Non-dedicated servers failing to load a game caused the introgame to be the server's game causing desyncs when people tried to join [FS#3960] (r20497) +- Fix: [NoAI] checking whether water tiles are connected failed in some cases [FS#4031] (r20489) +- Fix: Statues were not removed when towns would be removed (r20481) +- Fix: Do not spend cash when building a statue fails [FS#3985] (r20469, r20227) +- Fix: Adding 'goto nearest depot and stop' orders in one go was denied. This caused both AI adding those orders and backed up order restoration to fail [FS#4024] (r20441) +- Fix: For docks 'facing' north, i.e. having the watery part a the northern side, the station joiner had an off-by-one to the north w.r.t. the station spread against the actual other (correct) building tools [FS#4022] (r20438) +- Fix: Make snow on bridges depend on bridgeheight and make snowiness of bridgeheads depend on the tileheight at the entry [FS#3947] (r20424, r20423, r20422, r20421, r20420) +- Fix: During world generation the snow-mapbits are not yet available, so test the snowline variable directly (as they were before) [FS#4017] (r20418) +- Fix: PBS reservations were always displayed on halftile foundations if the railtype uses overlays [FS#4013] (r20408) +- Fix: Make the default minimum width for editboxes 10 pixels to prevent crashes [FS#4010] (r20394) +- Fix: Prevent buying more vehicles than allowed or buying companies when you'd get too many vehicles [FS#3993] (r20393, r20392, r20391, r20390) +- Fix: Initialise fund-industry buttons when opening window (r20386) +- Fix: Update cursor dimensions when reloading grfs resp. changing base graphics, so the cursor does not glitch if it becomes bigger (r20384) +- Fix: Stop vehicle following after zooming out [FS#3989] (r20361) +- Fix: [NoAI] Ship depots were constructed along the wrong axis [FS#4004] (r20348) +- Fix: Fallback font selection due to missing glyphs did not work as intended (r20296) +- Fix: When it is known the loading an old savegame is going to fail, bail out immediately (using an exception) instead of going on until e.g. the expected number of byte is read (r20247) +- Fix: The caption of the 'Available vehicle' lists was black, whereas for building those vehicles, which uses the exact same window, it was white (r20244) +- Fix: [NoAI] Clarify the documentation for AIBaseStation::GetLocation (r20238) +- Fix: Refit costs from refit orders are subtracted from the vehicle yearly income [FS#3988] (r20234) +- Fix: Road vehicles could be dead locked with one way roads. This allows one wayness to be removed if there are vehicles on a tile; it does not allow you to add one wayness to roads that have vehicles on them as it makes turning vehicles jump [FS#3961] (r20230) +- Fix: 'Service at nearest depot' behaved the same as 'Go to nearest depot' [FS#3986] (r20229) +- Fix: Depot did not become unsnowy, when snowline rises [FS#3976] (r20224) +- Fix: Strip non-printable characters before showing it in an edit box, so when renaming a vehicle type you will not get the 'SETX stuff' that some NewGRFs use [FS#3974] (r20220) +- Fix: NewGRFs that defined a vehicle without either loaded or loading groups could crash OpenTTD [FS#3964] (r20199) +- Fix: [NewGRF] GetNearbyTileInformation can be used to get the terrain type of a MP_VOID tile [FS#3963] (r20197) +- Fix: [NewGRF] Vehicle var FE bit 6 did return incorrect values for new railtypes (r20175) +- Fix: Inconsistencies w.r.t. to km/h vs km-ish/h as 'base' unit for aircraft speeds [FS#3870] (r20164) + + +1.0.3 (2010-08-01) +------------------------------------------------------------------------ +- Fix: Make it possible to properly assess the length of the rail toolbar caption, do not require '{WHITE}' control codes (r20242) +- Fix: Check for disallowed level crossings also when converting rail (r20237) +- Fix: Haiku uses a 'special' location for headers (r20219) +- Fix: Desync due to (temporary) wrong railtype; when loading a savegame the railtype of some (high ID) trains could be wrong [FS#3945] (r20137) + + +1.0.3-RC1 (2010-07-17) +------------------------------------------------------------------------ +- Feature: [NewGRF] Textstack support for CB 38 (r20086) +- Feature: [NewGRF] Add a railtype flag to disallow level crossings per railtype (r20049) +- Change: Improve desync debugging, crash log data and the Debian packaging (by making a debug symbols package) (r20138, r20136, r20129) +- Fix: Do not scan /data and ~/data (if they happen to be your working directory). If it is the directory where your binary is located it will still scan them [FS#3949] (r20166) +- Fix: Integer comparison failed in case the difference was more than 'MAX_UINT'/2 [FS#3954] (r20162) +- Fix: [YAPP] Converting a one-way block to a path signal with trains on both sides could lead to a train crash [FS#3937] (r20156) +- Fix: [NewGRF] Improve handling of snowing of railtypes and (infra)structures on foundations [FS#3883] (r20153, r20132, r20126, r20125) +- Fix: Ships were not marked as dirty when stopping inside a depot [FS#3880] (r20142) +- Fix: Some windows ignored all hotkeys [FS#3902] (r20141, r20140, r20139) +- Fix: Do not allow building a rail track to the water using a tree-tile [FS#3695] (r20110) +- Fix: [NoAI] AITown::GetRating() returned wrong values [FS#3934] (r20103) +- Fix: Reading deleted memory when selecting a NewGRF in the content download window of which the data has not been acquired from the content server. The crash would occur after the content server's reply was processed and the ContentInfo object was replaced with another [FS#3899] (r20089, r20082) +- Fix: If after loading a savegame (including intro game) one tried to save a game (including autosave) and that failed (very) early on because it could not open the file for writing all pointers would be converted to NULLs which then causes corrupted game states [FS#3786, FS#3887, FS#3920, FS#3923] (r20087) +- Fix: gitignore and hgignore had more missing/wrong entries (r20078, r20033, r20031) +- Fix: Remove the space between 'open' and 'ttd' in the title screen (r20077) +- Fix: Road vehicles could get crashed twice in a tick [FS#3896] (r20053, r20034) +- Fix: Coloured_news_year was stored in savegames while it should be a client setting [FS#3916] (r20051) +- Fix: Crash when spectator tried to open a vehicle list without selecting any company [FS#3892] (r20041) +- Fix: Instead of loading the intro game when loading a savegame fails on the dedicated server, generate a new game [FS#3907] (r20039) +- Fix: Tram tracks did not show at level crossing with the new railtypes [FS#3911] (r20036) +- Fix: Under some circumstances you could get into an infinite loop [CVE-2010-2534] [FS#3909] (r20035) +- Fix: The 64 bits TortoiseSVN was not always properly detected (r20029) +- Fix: Do not close the sort dropdown in the (original) vehicle list when there are no vehicles. That code is meant for the 'actions' dropdown [FS#3881] (r20014) +- Fix: When joining a company with a password you could only enter 20 characters of the password (r20012) +- Fix: Sign sorting was unstable [FS#3893] (r20009) +- Fix: Trains should also have running cost while slowing down for stop (r20006) +- Fix: [NewGRF] Stringcodes 82, 83 and 84 were not properly converted to openttd codes so they did not work (r20004) +- Fix: Clear force_proceed when entering depots and when loading, resetting of force_proceed on manual stopping did not work [FS#3878] (r19992) +- Fix: Do not show an error message when trying to start/stop a crashed plane [FS#3874] (r19953) +- Fix: Allow turning of roadvehicles while waiting in a queue (r19945) +- Fix: Disallow moving of vehicle news window [FS#3865] (r19943) +- Fix: Under some (unlucky) circumstances the wrong company would be 'current company' when changing company colour or orders [FS#3903] + + +1.0.2 (2010-06-19) +------------------------------------------------------------------------ +- Fix: Owner of the Waypoint View window was not properly set (r19990) +- Fix: Close list of vehicles with given oil rig in orders when the oil rig is deleted (r19956) +- Fix: Close list of vehicles with given buoy/oil rig in orders when switching company (r19955) +- Fix: Do not close list of waypoint's trains when the waypoint view is closed when it is sticky (r19952) +- Fix: Close buoy's vehicle list when the buoy is deleted [FS#3869] (r19951) + + +1.0.2-RC1 (2010-06-05) +------------------------------------------------------------------------ +- Feature: Translated desktop shortcut comments (r19884) +- Change: Name invalid engines, cargoes and industries 'invalid', if the player removed the supplying NewGRFs, hide invalid engines from the purchase list (r19879, r19877) +- Fix: When 'pause on new game' is set, pause the game before CleanupGeneration() to avoid conflicts with concurrent GUI code [FS#3857] (r19934) +- Fix: Pay for the rail/road when constructing tunnels, bridges, depots and stations [FS#3859, FS#3827] (r19925, r19887, r19881) +- Fix: Closing chatbox could cause glitches when news message was shown [FS#3865] (r19921) +- Fix: [YAPP] Inform the pathfinder as well about the fact that the backside of an one-way path signal can be a safe waiting point [FS#3803] (r19896) +- Fix: Allow loading savegames from the console without specifying the '.sav' extension, i.e. make it consistent with saving savegames from the console [FS#3761] (r19885) +- Fix: Dropdowns did affect positioning of new windows because they were not yet removed when the new windows were positioned [FS#3812] (r19883) +- Fix: [NoAI] AIEngine::IsValidEngine() and AIEngine::IsBuildable() returned false positives. Especially wagons of unavailable railtypes were reported available (r19880) +- Fix: Default vehicle group texts were drawn one pixel too low [FS#3851] (r19878) +- Fix: It was not possible to send all trains with common waypoint order to depot (r19876) +- Fix: Compilation for NetBSD [FS#3809, FS#3840, FS#3845] (r19874, r19859, r19853, r19781) +- Fix: If the (guessed initial) destination tile of a road vehicle was not a road stop but was a T-junction or turn, the road vehicles would jump around in circles [FS#3817] (r19873) +- Fix: When a network connection gets lost and a game with AIs was loaded the client might crash due to the AIs not being loaded while the game loop is executed [FS#3819] (r19869) +- Fix: Use non-breaking spaces for currency pre-/postfixes (r19867) +- Fix: Crash when changing/viewing locale settings in the console [FS#3830] (r19865, r19864, r19863, r19862) +- Fix: Drawing fallback sprites for unavailable NewGRF waypoints failed (r19852) +- Fix: Ensure that both texts of the NewGRF gui download button fit (r19823) +- Fix: Kicking clients by IP did not work [FS#3784] (r19818) +- Fix: Compilation with MinGW GCC 4.5.0 and UNICODE (r19787) +- Fix: If a waypoint is immediately followed by a path signal a reservation would be made from that path signal before the waypoint is marked passed. As a result the order to go to the waypoint is used to reserve the path after the waypoint and as such trains get lost [FS#3770] (r19784) +- Fix: NULL pointer deference when testing relative scope *action2 on an unbuilt engine [FS#3828] (r19782) +- Fix: Crash on too long paths [FS#3807] (r19780, r19779, r19778, r19777, r19776) +- Fix: MP_VOID tiles shall have no tropic zone [FS#3820] (r19769) +- Fix: Half-desert tiles would never revert back to clear tiles (r19768) +- Fix: Height in smallmap was different from measured heights [FS#3808] (r19767) +- Fix: [NewGRF] Vehicle var 43 missed AI information in purchase list (r19761) +- Fix: Blocked roadvehicles should first check whether they are still blocked before accelerating again, instead of continuous starting/stopping (r19755) +- Fix: Try harder to find a suitable font that can be loaded, i.e. while searching for a suitable font test whether you can open it [FS#3740] (r19753) +- Fix: Make sure the chat area fits in the default window size; if you want it larger, you can always change/override it in the config file [FS#3798] (r19751) +- Fix: [NewGRF] Industry var 0x43 is not 'safe' during callbacks 22 and 38 either (r19750) +- Fix: [NewGRF] Possible divide-by-zero if a NewGRF checked industry var 42 while the production level was 0 (r19749) +- Fix: Do not recenter usually centred windows when resizing main window or changing language, if they have been moved/resized before [FS#3675] (r19746) +- Fix: The GUI is controlled by _local_company, not _current_company (r19745) +- Fix: NewGRFs could access map bits of not yet constructed industries and houses during construction callbacks (r19748, r19743) +- Fix: [NewGRF] Passing some invalid data to industry variable 67/68 could cause a crash (r19713) +- Fix: Check for industry availability more thoroughly and cancel object placement when selecting not available industries [FS#3787] (r19701) +- Fix: Avoid showing building toolbars behind the main toolbar when the 'Link landscape toolbar' setting is active [FS#3781] (r19696) +- Fix: Under some circumstances the player's name could be empty (r19693) +- Fix: Do not show an error message when trying to give another client an amount of 0 money [FS#3779] (r19684) +- Fix: Do not display an error message when double clicking on a vehicle in the 'available vehicles'-window (r19669) + + +1.0.1 (2010-05-01) +------------------------------------------------------------------------ +- Fix: Crash when using restart via rcon (r19722) +- Fix: Leaking a file descriptor [CVE-2010-0406] [FS#3785] (r19695) +- Fix: Crash when the music/graphics metadata files were unreadable [FS#3774] (r19674) + + +1.0.1-RC2 (2010-04-22) +------------------------------------------------------------------------ +- Fix: Desync when joining the game because of using the wrong variable (r19687) +- Fix: Truncated archives were not detected when using zlib 1.2.3. This also fixes zlib 1.2.4 compatibility, zlib 1.2.5 is bug free (r19686) +- Fix: Towns with 3x3 and 2x2 road layouts could not expand (r19683) +- Fix: When joining a MP game all clients with company ID > 0 would be shown as if they were a spectator [FS#3775] (r19680) +- Fix: Client status was shown incorrect in the console (r19678) + + +1.0.1-RC1 (2010-04-17) +------------------------------------------------------------------------ +- Feature: [NewGRF] Support for extended text code 0x9A 11, print qword (r19570) +- Feature: Give more detailed error message when trying to build a too long bridge (r19561) +- Feature: Add rail speed limit to land area information window (r19556, r19434) +- Add: [NoAI] AIRail::GetMaxSpeed(RailType) to get the speed limit of railtypes (r19591) +- Change: Sync Debian packaging updates from Debian, but keep building a single package (r19572) +- Fix: Crash of a dedicated server if the null blitter is overridden and (after a while) there is no company 0 on new year anymore [FS#3749] (r19664) +- Fix: In rare cases, update of signals could be missed (r19663) +- Fix: Various improvements of command handling, missing error messages, improper validation causing crashes [CVE-2010-0402] [FS#3748] (r19658, r19657, r19656, r19655, r19654, r19637, r19633, r19621, r19616, r19605, r19604) +- Fix: Industry generation failed for large maps and lots of industry types (r19652, r19643) +- Fix: When a company is sold, move connected clients to spectators [FS#3745] (r19651) +- Fix: A client would not be properly moved when moved while joining, e.g. when entering a company's password. This caused the client to be in the wrong company (according to the rest of the clients) and the client being kicked on the first command [FS#3760] (r19648) +- Fix: Trains loaded above the original IDs did not have a default railtypelabel assigned to them, causing them to be unavailable. Could cause desyncs if the multiplayer game was not started from a savegame [FS#3768] (r19647) +- Fix: Do not allow building cacti outside of the desert or rain forest trees outside of the rain forest area. This to prevent people from thinking planting rain forest trees makes the rain forest bigger and thus adds more place to build a lumber mill [FS#3728] (r19644, r19635, r19634) +- Fix: Desync when taking over companies (r19636) +- Fix: Chat message caused glitch when rejoining a network game [FS#3757] (r19629) +- Fix: Desync when a command is received and in the queue while a client starts joining, i.e. save the game state. This can happen in two ways: with frame_freq > 1 a command received in a previous frame might not be executed yet or when a command is received in the same frame as the join but before the savegame is made. In both cases the joining client would not get all commands to get in-sync with the server (and the other clients) (r19620) +- Fix: Company related graphs were not updated correctly after changing the company colour [FS#3763] (r19615) +- Fix: Possible invalid read when server moves client to spectators before he finishes joining [FS#3755] (r19613) +- Fix: Crash when opening a savegame with a waypoint from around 0.4.0 [FS#3756] (r19612) +- Fix: Improve joining behaviour; kicking clients when entering passwords that was just cleared, 'connection lost' for people failing the password, access restriction circumvention [CVE-2010-0401] [FS#3754] (r19610, r19609, r19608, r19607, r19606) +- Fix: Desync debugging; false positives in the cache validity checks and saving/loading the command stream (r19619, r19617, r19602, r19601, r19600, r19596, r19593, r19592, r19589, r19587, r19586) +- Fix: Presence of online content was not properly updated after download due to duplicate slashes in the path (r19600) +- Fix: [NewGRF] Setting industry prop 0x24 to 0 caused empty station names (r19590) +- Fix: Crash when pressing 'h' (non-stop) in the order window of a ship or aircraft [FS#3744] (r19584) +- Fix: Graphs were not properly updated when going toggling keys (i.e. companies) (r19574) +- Fix: The timetable button was not automatically raised [FS#3739] (r19571) +- Fix: [NewGRF] Possible buffer underflow in NewGRF string code (r19569) +- Fix: [NewGRF] Do not return a random colour for unowned industries in var 45; TTDPatch does not seem to set the colour data in that case either and it could lead to desyncs (r19566) +- Fix: Window::OnResize() was not always called while resizing a window causing incorrect windows [FS#3730] (r19563, r19558) +- Fix: Bridge build error message should not show the same message twice (r19560, r19559) +- Fix: [NewGRF] During NewGRF loading, store rail type labels in temporary data and process after loading has finished. This avoids deactivated rail vehicles being reactivated if the climate property is set after the rail type property (r19557, r19502) +- Fix: Improperly scaled cargo payment graph when having lots of cargo (r19550, 19543) +- Fix: [NewGRF] Properties set before property 08 (house, industry, industry tiles) should be ignored, not trigger the NewGRF to be disabled [FS#3725] (r19547) +- Fix: Sorting industries by production was broken for NewGRF industries (r19538) +- Fix: Vehicle details window did not resize correctly after refitting a road vehicle to a longer variant [FS#3720] (r19533) +- Fix: Prevent drawing industries disabled at the smallmap as land tiles when they are built on water (r19523) +- Fix: Tunnels, bridges and road stops are build with only one roadtype (r19506) +- Fix: Remove same_industry_close setting did not do what it said and caused NewGRF trouble (r19499) +- Fix: Keep number padding intact when cloning vehicle names [FS#3710] (r19498) +- Fix: [NewGRF] Bytes and words get sign-extended for temporary/persistent storage (r19497) +- Fix: Stop reducing the size of the vehicle list after selecting a vehicle with a long description (r19480) +- Fix: Implement custom sound effect for helicopter take-off [FS#3668] (r19364) +- Update: Plural type of Slovak (r19452) + + +1.0.0 (2010-04-01) +------------------------------------------------------------------------ +- Fix: Network clients would crash while connecting to a server with AIs (r19526) +- Fix: [NPF] Crash when finding a waypoint before finding the closest depot [FS#3703] (r19460) + + +1.0.0-RC3 (2010-03-18) +------------------------------------------------------------------------ +- Feature: Append rail type speed limit (if set) to rail type selection list, and toolbar title (r19431) +- Feature: [NewGRF] Smallmap colours for railtypes (r19307) +- Change: Make the drive through and cargo list consistency checks only run when 'desync' debugging is enabled (r19403, r19398) +- Change: Update documentation for console command connect to use ip:port#company parameter format, in line with command line help (r19374) +- Change: [NewGRF] Increase railtype cost range (r19306) +- Fix: Mark industry windows dirty more often [FS#3701] (r19443) +- Fix: Custom group names are misaligned with default ones when using rtl languages [FS#3700] (r19438) +- Fix: With certain game settings one could clear tiles for free when building long roads (r19436) +- Fix: When loading a savegame created with a house NewGRF without that NewGRF available all houses became tall office blocks (r19435) +- Fix: Limit rail clearance earnings to 3/4s of rail build cost, to avoid money making loophole when rail build cost is less than rail removal earnings (r19433) +- Fix: Crash when the error message 'owned by ' was shown [FS#3696] (r19432) +- Fix: [NoAI] When the title game contains an AIPL block the AI settings where overwritten by those from the title game (r19429) +- Fix: Gracefully handle the case where we cannot open a .tar file (r19427) +- Fix: [YAPP] A train on a bridge/tunnel was not always found when checking for trains on a reserved path (r19425) +- Fix: [NoAI] The AI Debug window did not open if an AI or library fails to compile when loading a savegame [FS#3669] (r19395) +- Fix: One could not level the whole map anymore at once (r19392) +- Fix: Only show the 'No AIs available' error message when explicitly changing the number of AI opponents [FS3676] (r19389) +- Fix: [NoAI] When reloading a savegame, an AI failing to compile could trigger (trying) to read the not yet loaded information of another AI via the AI Debug window and its 'open with the most recently used AI' feature [FS#3666] (r19388) +- Fix: Close all orders windows when switching companies [FS#3671] (r19387) +- Fix: [IPv6] Netmask calculations were wrong if cidr >= 32 [FS#3684] (r19385) +- Fix: Overbuilding bridges, rail stations did not properly update PBS reservation [FS#3680] (r19384, r19383) +- Fix: [NoAI] List valuator could cause invalid iterators [FS#3665] (r19367) +- Fix: Close error messages about missing ownership when the company closes or is taken over [FS#3663] (r19358, r19357) + + +1.0.0-RC2 (2010-03-04) +------------------------------------------------------------------------ +- Feature: [YAPF] Consider the railtype imposed speed limit for pathfinding (r19301) +- Feature: BaNaNaS support for music sets (r19262) +- Feature: [NewGRF] Add 2 bits of pseudo-random data for rail types, based on tile location (r19235) +- Feature: [Windows] Add OpenMSX to the installer (r19220, r19219) +- Feature: [NewGRF] Add CB36 support for aircraft properties 0F and 11 (r19218) +- Feature: Scroll to current order destination when ctrl+clicking the start/stop bar (r19216, r19215) +- Feature: Concept of fallback base sets, i.e. do not automatically load the NoMusic/NoSound sets when there is another set; make NoSound part of base installations (r19214, r19213, r19212, r19211, r19206) +- Feature: Support for genders for cargoes, industries, vehicles, stations (r19180, r19179, r19178, r19177) +- Change: Increase the default small font size for freetype fonts as 6 point fonts are usually unreadable [FS#3655] (r19308) +- Change: [NewGRF] Railtype cost factor from byte to word value (r19306) +- Change: Improve error message with track building when signals are in the way (r19190, r19189) +- Change: Do not print the absolute path to AI script files in the AI debug window, use the relative path from /ai/ instead (r19166) +- Change: The Debian packaging; bring it in sync with the packaging used at Debian excluding package splitting (r19162) +- Fix: [Windows] Disable sound when a sound error happens instead of crashing [FS#3652] (r19304) +- Fix: [NewGRF] Return the TTD airport type in station var 0xF1 (r19299) +- Fix: [NewGRF] Segfault when station vars 0xF2/0xF3 is accessed when there is no truck/bus stop (r19298) +- Fix: [NoAI] Some methods of AIAbstractList left invalid iterators [FS#3566] (r19293) +- Fix: [YAPP] If reversing at path signals was disabled, a train would not reverse when hitting the back of an one-way signal (r19286) +- Fix: [NewGRF] Ensure prices cannot be set to zero. Zero prices break a lot of the internal logic to determine whether something has been done [FS#3646] (r19277) +- Fix: 'Cannot build here... in the way' showed the to-be-built industry twice, instead of the to-be-built industry and the industry that is in the way [FS#3618] (r19265) +- Fix: Writing (console) output to a file failed on Windows if the date would not be logged [FS#3639] (r19252) +- Fix: [NewGRF] Some GRF error messages did not free the previous error messages, creating a memory leak (r19251) +- Fix: With RTL languages clicking a horizontal scrollbar that could not scroll could cause a crash [FS#3643] (r19250) +- Fix: Start and end tiles were swapped in CMD_REMOVE_LONG_ROAD causing too much road to be removed [FS#3642] (r19249) +- Fix: DOS 'port' did not compile anymore (r19248) +- Fix: The -M command line option did not work (r19233) +- Fix: GetDestination() is invalid for nearest-depot orders (r19210) +- Fix: Compilation was broken for gcc 3.3 (r19207) +- Fix: The vehicle info in the autoreplace gui was drawn even when the window was shaded [FS#3634] (r19187) +- Fix: When selecting 'build many industries' in the scenario editor the 'build' button was not enabled [FS#3632] (r19176) +- Fix: Buoys are no Stations, only BaseStations (r19174) +- Fix: Under some circumstances timidity (via extmidi) would not shut down properly causing all kinds of trouble (e.g. blocked audio output). Try harder to shut down timidity and first shut down the music so shut down order is the inverse of initialisation order (r19168) +- Fix: Industry 0 could be chosen even if not available [FS#3631] (r19167) +- Fix: Vehicle running costs should not be changed in a running game [FS#3629] (r19165) + + +1.0.0-RC1 (2010-02-18) +------------------------------------------------------------------------ +- Feature: Allow to select different land colours for the smallmap (r19064) +- Feature: [NewGRF] Action 3/2/1 (i.e. new graphics) support for rail types (r19056) +- Feature: Add zoom-out to smallmap (r19039) +- Add: [NoAI] AIOrder::[G|S]etStopLocation to get/set the stop location of trains in a rail station (r19014) +- Change: Move home directory to a better place in Haiku [FS#3625] (r19151) +- Change: Do not load the 'new game' NewGRFs when you are certain the savegame would not have been saved with them, i.e. do not load the 'new game' NewGRFs for TTO savegames (r19044) +- Fix: Invisible depots draw the track, so also draw the overlays (r19154) +- Fix: [v]seprintf should return the number of added characters excluding '\0' on truncation [FS#3627] (r19149, r19148) +- Fix: [YAPF] Look-ahead for multitile waypoints 'made up' data that should not go into the cache, causing desyncs in MP [FS#3619] (r19141) +- Fix: Report a more useful error when failing to build a bubble generator (r19137) +- Fix: Resize station cargo widget when needed to display all accepted cargo types [FS#3617] (r19123) +- Fix: [NewGRF] Industry property 0x17 was interpreted incorrectly and in some cases circumvented the density difficulty setting (r19120) +- Fix: Removing towns (in the scenario editor) that had stations/depots refer to them or vehicles were on the town's road could cause a crash [FS#3616] (r19119) +- Fix: In the order window the Non-stop dropdown was not enabled for depot and waypoint orders and some buttons were raised too soon [FS#3593] (r19118, r19117) +- Fix: Do not crash on broken lng file and prevent it from happening again [FS#3611] (r19113, r19112) +- Fix: Not all news data was properly freed when starting a new game [FS#3614] (r19105) +- Fix: The BeMidi driver was broken [FS#3610] (r19097) +- Fix: Crash when one of the items in the news_display group in the config file has no value (r19096) +- Fix: Crash when a base set has an empty metadata field (r19095) +- Fix: Possible read/write after free when the client triggered the server to close the connection [FS#3599] (r19072) +- Fix: Remove Bidi control characters from the reordered text so they are not drawn [FS#3604] (r19067) +- Fix: [NewGRF] Settings that are part of the 'TTDPatch flags' can cause desyncs if they are changed in network games (r19066) +- Fix: When banning yourself via rcon do not send the 'command response' to the client as the connection has already been terminated [FS#3598] (r19054) +- Fix: Mass stopping/starting/autoreplacing gave empty errors when there were no vehicles [FS#3577] (r19024) +- Fix: City airport introduction date had become 5 years later (r19023) +- Fix: Loading old (0.1-ish) savegames failed (r19022) +- Fix: Do not NULL the pointers when saving the savegame on an error during saving; the savegame is still valid, so do not make it invalid [FS#3570] (r19021) +- Fix: When removing roads, the player was also charged for removing the foundations [FS#3591] (r19016) + + +1.0.0-beta4 (2010-02-04) +------------------------------------------------------------------------ +- Feature: Content mirroring support (r18994) +- Feature: Show empty query after creating new group (instead of 'Group nnn') (r18981) +- Feature: [NewGRF] NewGRF-settable rail type properties, increase number of possible rail types, per rail type speed limits (r18970, r18969) +- Feature: [NewGRF] Allow layering of multiple groundsprites in spritelayouts of stations, houses and industrytiles; so hacks with zero-sized bounding boxes are no longer needed and no longer cause trouble (r18959) +- Feature: [NoAI] Introduce GetBuildCost functions in several classes to get easier cost estimations before you start building (r18955) +- Feature: [NoAI] Allow editing AI settings while an AI is running (r18953) +- Feature: Make it possible to change newgame settings from within a game via the console (use setting_newgame instead of setting) [FS#2885] (r18943) +- Feature: Add a setting to reduce/disable aircraft crashes [FS#2678] (r18942) +- Feature: Make the crash position of aircraft a bit random by giving aircraft a chance to crash every tick they are breaking (r18940) +- Change: [NoAI] Use the highest version of an AI that can load the AI data from a savegame instead of the exact same version [FS#3232] (r18944) +- Fix: Off-by-one in the music playlist (song missing) [FS#3588] (r18997) +- Fix: [NewGRF] industry var A5 (=high 8 bits of var A4) returned the high 8 bits of var A2. Same problem for 9B/9A/98 (r18988) +- Fix: [NoAI] Make building long rails fail for AIs if there is an obstacle in the way (r18987) +- Fix: Possible invalid memory access when merging companies [FS#3584] (r18978) +- Fix: Estimating the cost of removing statues could clear the presence flag in the town (r18976) +- Fix: CMD_BUILD_ROAD missed CMD_AUTO. Also do not access tiles anymore after clearing them; that fails either in test or exec run [FS#3578] (r18974) +- Fix: Train acceleration for original acceleration model was not updated if the train's power changed (r18971) +- Fix: Make sure the values of settings loaded from a savegame are valid (r18950) +- Fix: After clicking move up/move down in the NewGRF/AI the selected item could be out of range [FS#1510] (r18948, r18947) +- Fix: It was possible to change AI settings without changing to the custom difficulty level by using the query text window (r18946) +- Fix: Remove the loading indicators as soon as a train crashes [FS#3575] (r18941) +- Fix: [NewGRF] Industrylayout's special water tile check did not properly check for crossing north border of map (r18938) +- Fix: [NewGRF] Value of variables 90 and 91 were not what NARS expects [FS#3551] (r18935) +- Fix: [Windows] In some rare case a deadlock could happen when stopping sound driver (r18934, r18913, r18892) +- Fix: [NoAI] Autoreplace is also valid for the default group (r18930) +- Fix: Preserve some timetable related vehicle flags during autorenew/-replace [FS#3568] (r18929) +- Fix: AIOrder::GetOrderDestination could return a non-waypoint tile when the waypoint was a multitile waypoint [NoAI] (r18924) +- Fix: On bankruptcy the company value did include the loan and as such the value at which you bought the company was too low [FS#3561] (r18908) +- Fix: Writing LZO-compressed savegames would produce invalid files and potentially overwrite memory (r18904) +- Fix: [Windows] File locations for Windows were not documented correctly for all versions of Windows [FS#3562] (r18903) +- Fix: Pressing cancel for the query windows of the world generation window caused the default to be set instead of no changes to the value [FS#3558] (r18896) +- Fix: Avoid duplicate path separator when searching for PNG files which prevented tar-lookups (r18891) +- Fix: [NewGRF] Perform bounds checking for all NewGRF data reads. Explicit length checks (which were not always correct) are no longer needed so these are removed to simplify code (r18884) +- Fix: Aircraft can be send to an hangar when the target airport has one and when it can land, not only when it has a plane terminal (r18880) +- Fix: [NewGRF] Crash when a NewGRF used var62 in an industry tile chain when the industry tile was part of an original industry (r18878) + + +1.0.0-beta3 (2010-01-21) +------------------------------------------------------------------------ +- Feature: Make building (long) roads work like building rail; build upon the first obstruction instead of failing totally [FS#3318] (r18803) +- Feature: Allow user customisable compression levels for the zlib compression (r18772) +- Feature: [NoAI] Rerandomise AIs on reloading (via the debug window) when they were randomly chosen [FS#3095] (r18763) +- Feature: [NewGRF] Implement VarAction2Houses variables 66 and 67 (r18736) +- Change: [SDL/Allegro] Make the number of samples/frequency runtime configurable (r18821, r18820) +- Change: Be consistent with airport naming [FS#3493] (r18819) +- Change: [NewGRF] Consider callback 19 only broken after subcargoes 0 to 255 have been used, instead of stopping at 15 (r18774) +- Change: Replace MiniLZO with the real library (r18769) +- Fix: Town noise population settings could not be changed in-game [FS#3532] (r18864) +- Fix: Do not pass AI strings through iconv [FS#3544] (r18862) +- Fix: Do not do screen redraw when the landscape contains broken slopes [FS#3540] (r18850) +- Fix: Default-waypoint was drawn incorrectly for monorail and maglev in the waypoint picker (r18841) +- Fix: In some cases error messages were not properly sent to the client before closing the connection. As a result the client would say 'connection lost' when the cause was something completely different (r18801) +- Fix: In some cases with invalid packets one can crash OpenTTD (r18800) +- Fix: [SDL] Possible deadlock when killing OpenTTD while starting it [FS#3521] (r18796) +- Fix: When copying an 'image' back into the buffer the 32bpp anim blitter triggered palette check of the whole window instead of only the part the got copied back [FS#3504] (r18791) +- Fix: Viewport could jump under high CPU load [FS#3515] (r18790) +- Fix: Crash when getting the tooltip of the industry amount in the world generation window [FS#3516] (r18787) +- Fix: [NoAI] NoAI's custom implementation of DoCommandP has several flaws (not masking of bits, not resetting town authority updates on checks/estimates, ...). Let it use DoCommandPInternal, DoCommandP without showing error messages and such, instead [FS#3507] (r18786) +- Fix: [NoAI] AIs did update their last cost incorrectly in network games if the cost of the DC_EXEC phase differed from the ~DC_EXEC phase (r18781) +- Fix: [YAPP] Remove a special check for two-sided signals when reserving a path as this causes trains to get stuck in front of them [FS#3483] (r18778) +- Fix: Assertions because the unloading and signal wait counter got into each others way [FS#3422] (r18764) +- Fix: [NewGRF] Spritelayouts do not need an Action 1 if only using default sprites [FS#3497] (r18761) +- Fix: [NewGRF] Action 9 did not properly detect whether an Action 8 was encountered already [FS#3500] (r18760) +- Fix: [NewGRF] Do not segfault when a NewGRF contains an Action 2 and Action 3 but no Action 0 (r18759) +- Fix: [NewGRF] CircularTileSearch skipped a few tiles close to the starting tile, as a result some NewGRF houses could be placed too close together [FS#3495] (r18755) +- Fix: The cargo payment button states were not properly set on opening the window [FS#3492] (r18750) +- Fix: [NoAI] The AI's name and version in the debug panel was not properly centred [FS#3491] (r18749) +- Fix: Clear the cached NewGRFs of a server when receiving a reply instead of when requesting the information. With slow/unstable network connections it would look like the NewGRF settings button went randomly missing [FS#3489] (r18746) +- Fix: Do not toggle the sticky- and shading-button twice per mouseclick when clicking fast [FS#3487] (r18744) +- Fix: [NewGRF] House prop 1D was trashed when a NewGRF contains prop 14 after prop 1D (r18742) +- Fix: Building trees on snow with rocks underneath caused an assert [FS#3501] (r18739) +- Fix: When a tree died while there was snow the amount of snow on the tile changed (r18738) +- Fix: [NewGRF] VarAction2Station variable 67 was not swapped properly for orientation (r18737) + + +1.0.0-beta2 (2010-01-05) +------------------------------------------------------------------------ +- Feature: Do not delete the rough/rocky status of a tile when it is covered by snow, this allows rocky tiles under snow if you have a variable snowline (r18719) +- Feature: [NewGRF] Add support for custom station foundation graphics (r18708) +- Feature: Allow virtually paying a percentage of the leg profit in feeder chains. This to give the user a better chance to get a feeder system without 'losses' (r18703) +- Feature: Configurable slope steepness for trains from 0% to 10%, default is 3% as before [FS#3459] (r18674) +- Feature: Allow contour-map to be shown with coloured industries in smallmap [FS#567] (r18665) +- Add: [NoAI] AIEngine::IsBuildable to check if you can build a certain engine (r18687) +- Change: [NoAI] Merge buoy and waypoint functions (r18725) +- Change: [NoAI] AIEngine::IsValidEngine will now also return true when you have at least one vehicle of that type even if you cannot build it anymore (r18687) +- Change: Update Squirrel from 2.2.3 to 2.2.4 (r18639) +- Fix: New viewports did not centre on the correct position [FS#3414] (r18730) +- Fix: The lock in the company window was only drawn for your own company [FS#3427] (r18729) +- Fix: Some invalid gender/plural indices in strings, which could eventually cause crashes [FS#3480] (r18727) +- Fix: With non-uniform industries the 'supplies' text when building a station could be incorrect (missing a cargo) [FS#3463] (r18726) +- Fix: Refitting a non-refittable vehicle to its default cargotype failed, causing problems for AIs [FS#3475] (r18724) +- Fix: The join station window did not account for scrolling, so if you did scroll the station was not joined with the selected station [FS#3476] (r18713) +- Fix: The wrong town is mentioned in the error when trying to make one way roads of town owned roads [FS#3478] (r18710) +- Fix: Animation buffer for 32bpp-anim blitter was only validated during sprite blitting, other drawing operations did not check it. Initial startup and window resize could therefore lead to crash [FS#3464] (r18709) +- Fix: Enable DrawGroundSpriteAt() to deal with foundations as DrawGroundSprite() does, and use this for drawing one-way-road-signs and clear-land-fences [FS#3467] (r18702) +- Fix: When deleting an industry on water (oil rigs) the tiles on water were not marked dirty (r18700) +- Fix: [NewGRF] GRF parameters were not properly initialised to zero, and not always checked for valid range (r18699) +- Fix: Crash when scrolling to an item removed by filtering in the 'add NewGRF window' [FS#3471] (r18697) +- Fix: [NoAI] AITile::IsCoastTile returned false for coast tiles with trees on them [FS#3404] (r18696) +- Fix: After a company went bankrupt it was impossible to build a new waypoint close to a deleted one until the grey sign was gone (r18692) +- Fix: Some keys that open windows that want to be located relatively to the toolbars/statusbar could cause a crash when in one of the end game screens [FS#3469] (r18690) +- Fix: In some cases _sl.chs is used when not initialised. As _sl.chs always refers to a single table when initialised replace _sl.chs with the actual table [FS#3470] (r18686) +- Fix: [NewGRF] Tile area of waypoints was not correctly given to NewGRFs in case of multi tile waypoints (r18679) +- Fix: [NewGRF] If an action B did not have a 'data' string but would print it OpenTTD would segfault [FS#3452] (r18671) +- Fix: Update all tiles when snowline height changes in larger steps than one tile [FS#3455] (r18670) +- Fix: [NoAI] Crash when trying to get the order destination of a 'nearest depot' order [FS#3454] (r18667) +- Fix: Aircraft on the metropolitan airport took a long route to the closest loading pad [FS#3169] (r18661) +- Fix: [NewGRF] Wrong strings drawn for cargo subtype in vehicle details [FS#3443] (r18658) +- Fix: When trying to attach a wagon to an existing free wagon chain, do not attach it to itself [FS#3442] (r18653) +- Fix: [NoAI] When AI tried to create NO_UNLOAD order, GOTO_NEAREST_DEPOT order was created instead [FS#3438] (r18651) +- Fix: [YAPP] Treat the backside of an one-way path signals as a safe waiting point [FS#3430] (r18648) +- Fix: [YAPP] A train inside a station was not always found when checking for trains on a reserved path (r18647) +- Fix: [YAPP] Do not extend the reserved path through a newly built path signal directly in front of a stopped or loading train. Also restore the reserved path in more cases after removing a signal [FS#3418] (r18646) +- Fix: Company league window was too narrow [FS#3434] (r18644) +- Fix: Rotation could not be changed for heightmaps [FS#3436] (r18643) +- Fix: When a company goes bankrupt and has vehicles on a drive through road stop that is not theirs, the 'filled' cache of the road stops would get corrupted [FS#3432] (r18642) +- Fix: Downloading music sets would fail (r18638) +- Fix: Crash when invalid pointers are left due to saveload failing at e.g. decompressing the savegame [FS#3421] (r18634) +- Fix: When making a screenshot the name of the previous screenshot went missing in the 'successful screenshot' message and the console command would be shown twice [FS#3419] (r18631, r18630) +- Fix: (un)loading counter being reset while loading a train and changing the (path) signal setup around the station [FS#3422] (r18628) +- Fix: {CARGO} takes 2 parameters, not 1. This made {N:XYZ} commands after CARGO mess up their indices and that then triggered an assertion [FS#3425] (r18626) + + +1.0.0-beta1 (2009-12-24) +------------------------------------------------------------------------ +- Feature: Music replacement sets, like graphics and sound replacement sets (r18608) +- Feature: Add shading and unshading of windows [FS#2943] (r18588) +- Feature: Initially select the last joined server when going to the server list [FS#3311] (r18578) +- Feature: Additional map variety option for TGP landscape generator (r18541) +- Feature: Add the possibility to not make new tree tiles in-game (r18522) +- Feature: Moving of AIs in the AI configuration window [FS#3359] (r18516) +- Feature: Make maximum pathfinder penalties for finding depots customisable, also increase it slightly to 20 tiles worth of penalties (r18481) +- Feature: [Strgen] Allow G and P to 'select' substrings of STRINGn for getting their gender (r18444) +- Feature: Make penalty for road stop occupancy user configurable (r18404) +- Feature: Fully scalable, by font size and content, GUI and improved right-to-left language support [FS#1905] (r15800-r18350) +- Feature: Set the start time of a timetable (r18294) +- Feature: Show the expected arrival/departure dates in the timetable window (r18285) +- Feature: [NewGRF] Add new price bases for removing industries, building/removing unmovables (new objects), building/removing rail-waypoints/buoys, interacting with town-authority, building foundations, funding primary industries (when not prospecting) and towns (r18283) +- Feature: Founding towns in-game (r18281) +- Feature: [NewGRF] Make price base multipliers related to vehicles only apply to the GRF locally, if it defines engines of that type itself (r18268) +- Feature: [NewGRF] CB 36 for roadvehicle property 09 'running cost factor' (r18011) +- Feature: Non-automatic screenshot name can be entered in console (r17938) +- Feature: Make it possible to disable background saving, only via the config file/in game console though [FS#2633] (r17893) +- Feature: Automatically select the railtype with the most engines for the autoreplace window/try to avoid showing an empty autoreplace list [FS#1760] (r17892) +- Feature: Show maximum tractive effort in the 'exclusive test'/'early offer'/'engine preview' window [FS#1619] (r17891) +- Feature: Double clicking on a NewGRF opens the parameters window (r17890) +- Feature: Double click on a item in the refit list refits without the need to click on the refit button (r17889) +- Feature: [NewGRF] Textstack support for CB 37 [FS#1862] (r17802) +- Feature: [OSX] Implement automatic fallback font selection for OSX (r17794) +- Feature: Translatable base sound/graphics set descriptions (r17790) +- Feature: Show the nickname of the person you are PMing [FS#3116] (r17741) +- Feature: [OSX] Add a MIDI driver using Cocoa/CoreAudio [FS#3223] (r17710) +- Feature: [OSX] Implement clipboard support for OS X [FS#2053] (r17708) +- Feature: Possibility to choose (randomise or enter custom) town name before its creation (r17612) +- Feature: [NewGRF] Callbacks for houses to disable drawing foundations and to disable slope changes, like industry tile callbacks 30 and 3C (r17558) +- Feature: [NewGRF] Implement callback 145 (custom station rating) (r17547) +- Feature: Filtering in Add-NewGRF dialogue (r17541) +- Feature: Add the date to all logging in the (real, not in-game) console if show_date_in_console is set. For dedicated server binaries the default is 'on', for the rest it is 'off' [FS#2339] (r17488) +- Feature: Reconnect console command (r17466) +- Feature: Allow building rail stations over existing rail without signals but will upgrade normal rail to electrified rail if necessary (r17460) +- Feature: Crash logger for all Unixy OSes in a similar way as the Windows crash logger (r17453) +- Feature: Open the 'Rename group' dialogue after creating new group (r17281) +- Feature: [NoAI] Older API compatibility wrappers, so one can get the 0.7 API in later versions while keeping the real API clean (r17214) +- Feature: The Windows installer can now optionally download OpenGFX and OpenSFX (r17191) +- Feature: Sort vehicle lists on (timetable) delay [FS#2945] (r17182) +- Feature: Localised decimal separator (r17157) +- Feature: Improved the sample rate conversion a bit (r17146) +- Feature: Allow higher sample rate and higher quality samples (r17140) +- Feature: Sound replacement sets, like graphics replacement sets (r17139) +- Feature: Multi tile waypoints (r17002, r17000, r16993) +- Feature: [NewGRF] Turn variable 0E/8E (vertical offset for trains in depot) and variable 1E/9E bit 3 (wagon width in depot) into grf-local variables (r16867) +- Feature: Highlight whole articulated vehicles in traindepot instead of only the first part (r16818) +- Feature: Ability to enter server and company password via command line when joining a server [FS#570] (r16555) +- Feature: Give the town generator a slight tendency to build towns near water by not discarding watery random tiles but by searching for near land [FS#2635] (r16147) +- Feature: Configurable digit group separator per language with user override (r16129) +- Feature: Make the first 4 rail building tools behave more like autorail (r16095) +- Feature: Allow sorting stations by the lowest cargo rating instead of only by the highest cargo rating [FS#597] (r16045) +- Feature: Allow filtering of vehicle purchase lists by cargo [FS#1941] (r16042) +- Feature: Allow (per order) to let a train stop at the near end, middle or far end of a platform from the point of view of the driver of the train that enters the station (r16037) +- Feature: Listen on multiple IPs/sockets and register all IPs to the master server (r16014, r15975, r15973, r15971) +- Feature: Full IPv6 support (r16000) +- Feature: Allow train vehicles to be shorten to 1/8 length, even if not at the end of the train (r15793) +- Add: [NoAI] AIOrder::AIOF_GOTO_NEAREST_DEPOT for goto nearest depot orders (r18518) +- Add: [NoAI] Enable the squirrel standard math library (r17498) +- Add: [NoAI] A vehicle list for all vehicle that are ordered to a specific depot (r17486) +- Add: [NoAI] AISubsidy::SubsidyParticipantType, AISubsidy::GetSourceType, AISubsidy::GetSourceIndex, AISubsidy::GetDestinationType, AISubsidy::GetDestinationIndex for better subsidy management (r17115) +- Change: Forbid industries to clear sea/river when levelling land (r18554) +- Change: Make it visible when you are to pass the next signal on danger and possible to cancel it (r18515) +- Change: Move the 'check online content' button from the AI list window to the AI configuration window. This makes it consistent with the NewGRF windows [FS#3340] (r18507) +- Change: Use zÅ‚ instead of zl for the Polish Zloty [FS#565] (r18434) +- Change: Show different texts in town GUI when the town does not need food the whole year to grow (r18433) +- Change: Make road vehicles behave more like trains 'around' stations and use pathfinder penalties to determine to which 'part' to go (r18382) +- Change: Do not split up articulated vehicles in the train details view. If an articulated vehicle it too 'wide' draw the information on the next line and if there are multiple cargoes split that over multiple lines too [FS#2923] (r18344) +- Change: Make pause on join pause during the whole joining (including download) phase [FS#3287] (r18054) +- Change: Prefer extmidi over allegro midi and allegro over null driver [FS#3272] (r17875) +- Change: Several improvements to the performance of CargoPackets/CargoLists; time spent in those functions reduces by 55-85% (r17840, r17836, r17818, r17814, r17812, r17801, r17736, r17735, r17733, r17731, r17730) +- Change: [SDL] Make 'update the video card'-process asynchronous. Improvements of 2%-25% (real time) during fast forward on dual core/hyperthreading-enabled CPUs (r17776) +- Change: [NoAI] Make AIEngine:CanRefitCargo() not report refittability to Mail by default for aircraft. It is not necessarily true, and the special case of carrying both passenger&mail is better handled by AIs themself than by the API (r17719) +- Change: [OSX] Do not use deprecated methods/undocumented functions [FS#1411] (r17712, r17711) +- Change: Make SDL's video driver more likely to be loaded than Allegro's video driver; SDL seems to perform better (r17583) +- Change: Do not assume that there is always 'another' industry tile after two '0x18' industry tiles (r17521) +- Change: Make the performance ratings harder to exploit; only count profitable vehicles and recently serviced stations [FS2459] (r17485) +- Change: When removing a station or waypoint keep the rail unless Ctrl is pressed. This makes the behaviour consistent between the two (r17471) +- Change: Show the client id in join messages at the server (r17467) +- Change: NewGRF price modifiers now take effect every time when loading NewGRFs instead of once on gamestart (r17433) +- Change: Make a distinction between missing and corrupted data files. If (at least) one data file is missing do not consider the set to be usable. Do also no autodetect sets with missing files (r17241) +- Change: Update MiniLZO to 2.0.3 (r17215) +- Change: Update Squirrel to 2.2.3 (r17195) +- Change: Remove UNICODE notice in windows installer (r17186) +- Change: Apply the subsidy when subsidy's destination is in station's catchment area and cargo packets originate from subsidy's source [FS#265,FS#2094,FS#2589] (r17113) +- Change: Subsidies are not bound to stations after awarding anymore, they still apply to town or industry, no matter what station is used for loading and unloading. Awarded subsidies from older savegames are lost [FS#1134] (r17113) +- Change: [NoAI] Add AIBaseStation as a parentclass for AIStation and AIWaypoint, and move GetName, SetName and GetLocation to AIBaseStation (r17011) +- Fix: Conditional orders were seen as 'valid' and as such aircraft with only conditional orders did not crash (r18615) +- Fix: Pressing default for the starting year/snow line height edit boxes of the world generation windows did not work [FS#3398] (r18586) +- Fix: [OSX] Try to get a generic RGB colour space if getting the system colour profile failed [FS#3198] (r18573) +- Fix: [NewGRF] House property 15 did not work [FS#2613] (r18567) +- Fix: Do not try to overtake a vehicle in a road station as overtaking in a station is not allowed [FS#3390] (r18561) +- Fix: Make aircraft behave the same on autoreplace/autorenew as other vehicle types (r18553) +- Fix: First do the time-since-last-service check and only then determine whether autoreplace needs to take place. This way they will not keep autoreplacing continuously on failure, but only after some timeout. Also check some minimal requirements (engine availability, refittability) and a heuristic for the needed money when sending vehicles for autoreplace [FS#1762] (r18551, r18549) +- Fix: Do not account for path reservation costs when entering a signal block via a 'block' signal. This way you will not get double penalties, both red signals and reservation costs, for the block signalled tracks [FS#2722] (r18535) +- Fix: [NewGRF] An industry NewGRF that defined a too small size for action0 prop 0A could cause a crash (r18527) +- Fix: Allegro does not like to work with extmidi, so warn the user about that [FS#3272] (r18520) +- Fix: When you pass a signal at danger, in a PBS controlled area, do not try to do the 'safe' thing and stop, but continue going; the user wanted the train to pass the signal at danger so (s)he has to suffer the consequences. Of course one can always stop the train manually [FS#2891] (r18515) +- Fix: No error message was created for the first fatal NewGRF error [FS#3368] (r18506) +- Fix: Improve airport movement on several airports [FS#3169] (r18505) +- Fix: Autoreplace and autorenew always reset their cargo sub type to 0. Now find a sub cargo type with the exact same name and use that, otherwise fallback to 0. So cargo sub types can be maintained via autoreplace *if* the new vehicle supports the same cargo sub type [FS#3159] (r18499) +- Fix: Cloning of vehicles could create vehicles with invalid cargo sub types for the build year of the vehicle. Fall back to another cargo sub type with the exact same name, otherwise fallback to cargo sub type 0 [FS#2616] (r18498) +- Fix: [NewGRF] Direction is accounted for long before motion counter is updated (r18479) +- Fix: Moving vehicles around/selling vehicle in the train depot could create states that are not allowed by the NewGRF attach callback [FS#3146] (r18472, r18470) +- Fix: Unselect an AI in the AI Settings window when it falls out of the range of active AIs [FS#3357] (r18436) +- Fix: Road vehicles would not pick an empty drive through stop. Now they will *if* the penalty for driving around is less than the occupancy penalty [FS#1944] (r18404) +- Fix: Long (articulated) road vehicles could block loading of others when the following road vehicle already got 'permission' to go to the next bay even when it could not reach it [FS#1495] (r18404) +- Fix: The tree 'which one to draw' hash was not anywhere near random and thus showed a very visible repeated pattern when only one tree type was used [FS#3343] (r18398) +- Fix: [NoAI] Make AIIndustryType::GetConstructionCost() return -1, if the industry is neither buildable nor prospectable (r18276) +- Fix: Use free type ascender/descender metrics to position font offset correctly (r18096) +- Fix: Make the 'pause' chat message when actually executing the pause command. This to prevent showing paused and especially unpaused to be shown when the state does not change. Output now mentions whether pause changes keep the game paused and what reasons for pausing there 'currently' are (r18052) +- Fix: [NoAI] Improve behaviour of (AIEngine|AIEventEnginePreview)::GetCargoType() and AIEngine::CanRefitCargo() wrt. articulated vehicles (r17898) +- Fix: [NewGRF] CB15 and CB36 (capacity) were not always called when they should [FS#3255] (r17897) +- Fix: Invalidate cache of vehicle vars 40-43 after testruns of certain commands, that change them temporarily (r17894) +- Fix: [OSX] The splash image was not displayed if the Quartz video driver was used (r17793) +- Fix: Do not let aircraft drive a while over the grass when landing at high altitude airports [FS#3259] (r17762 +- Fix: Make the -c location relative to the current directory instead of the directory of the binary [FS#3247] (r17686) +- Fix: Some semaphore signals fell outside of the signal GUI. Now the signals are properly centred which should make that problem go away [FS#3242] (r17657) +- Fix: Some inconsistencies with the difficulty settings in the scenario editor. Also re-enable changing some difficulty settings (e.g. max loan) in the scenario editor [FS#3219] (r17644) +- Fix: Do not accept cargo produced in the same industry; generalise and improve the check used only for valuables (r17437) +- Fix: Pay only for cargo actually delivered, not for all cargo unloaded at station; can differ with 'stockpiling' industries (r17436) +- Fix: Improve movement of aircraft; do not make turns bigger than 45 degrees while in flight, do not move while turning on the ground (r17415, r17405) +- Fix: Crash in order GUI when changing some orders with both the mouse and keyboard at the exact same time [FS#2859] (r17384) +- Fix: Trains would not show smoke if the load/unload counter was not 0, though there does not seem to be a reason to check that variable anyhow anymore [FS#3162] (r17352) +- Fix: One was not offered to take over bankrupt companies anymore; caused by the introduction NoAI, although NewAI had the same problem too [FS#2769] (r17345) +- Fix: Minor improvements of the airport state machines (r17338, r17337, r17334) +- Fix: Road vehicles forgetting their servicing order when the path takes them away (in bird distance) from their destination first [FS#3057] (r17333) +- Fix: Mention of Ctrl modifier was missing from some tooltips [FS#3120] (r17300, r17297) +- Fix: Keep vehicle news and viewports following vehicles, when autoreplacing/renewing them [FS#3048] (r17147) +- Fix: Inconsistency between signs of stations and waypoints [FS#3081] (r17040) +- Fix: NewGRF stations would be triggering assertions for waypoints all over the place when using the more advanced station types [FS#2996] (r16909) +- Fix: Skipping a 'nearest depot order' because none could be found could cause multiple orders to get skipped [FS#2925] (r16457) +- Fix: Makedepend cannot handle the amount of files we have and it also miss some dependencies. So use our custom implementation of makedepend (r16307) +- Fix: Autopause and manual pausing conflict with each other, new game + pause on new game + autopause make the game not unpause on the first join [FS#2864] (r16242) +- Remove: [NoAI] AIVehicle::SkipToVehicleOrder as it was a duplicate of AIOrder.SkipToOrder (r18504) +- Remove: OPF for RVs and NTP for trains; both the oldest path finders (r18362) +- Remove: Support for gcc2. It has not been able to compile OpenTTD for months. All attempts to do another workaround failed (r16492) + + +0.7.5 (2009-12-23) +------------------------------------------------------------------------ +(None) + + +0.7.5-RC1 (2009-12-14) +------------------------------------------------------------------------ +- Add: Some missing latin-ish characters from the OpenGFX set (r18431) +- Change: Recolour the bubble generator just like any other industry [FS#3349] (r18409) +- Fix: Read after free in case no network connection could be made with the content server (r18493) +- Fix: [NewGRF] Initialisation of cargo payment was broken for NewGRF cargoes [FS#3344] (r18475) +- Fix: [NoAI] AIOrder::SkipToOrder did not properly resolve ORDER_CURRENT (r18471) +- Fix: When moving a wagon and only the last part of a dual headed engine you could split the dual headed engine over two vehicles. This could be used to crash servers [CVE-2009-4007] (r18462) +- Fix: [Windows] Forgot to load the symbol from SDL.dll (r18439) +- Fix: Do not run the 'jam protection' for vehicles in a depot [FS#3360] (r18428) +- Fix: [Windows] The help window would be too large in some cases [FS#3327] (r18424) +- Fix: Under some circumstances a pointer could be left untouched and then freed. Make sure this does not happen by ensuring it starts out as NULL instead of 'garbage' [FS#3298] (r18418) +- Fix: On slopes the original and better road layouts did not check their minimum distance requirements [FS#3332] (r18415) +- Fix: Aqueducts were not influenced by the 'long bridges' setting [FS#3338] (r18407) +- Fix: Drive through road stops did not get flooded (r18401) +- Fix: [YAPP] Trains on bridges were not found, when searching for the origin of a reservation [FS#3345] (r18392) +- Fix: (Invalid) GRFs could trigger invalid reads (r18391) +- Fix: One could not share orders between buses carrying different cargoes (r18380) +- Fix: Off-by-one in the preconfigured music lists [FS#3339] (r18369) + + +0.7.4 (2009-12-01) +------------------------------------------------------------------------ +- Fix: Endianness issue with saving the zoom level [FS#3333] (r18351) +- Fix: [NewGRF] When starting a new game the values of action D variable 13 were incorrect [FS#3324] (r18207) + + +0.7.4-RC1 (2009-11-15) +------------------------------------------------------------------------ +- Change: Prefer extmidi over allegro midi and allegro over null driver [FS#3272] (r17875) +- Change: [NewGRF] Apply default refitmasks only when the NewGRF did not set any of the three refittability properties (xor mask, positive classes, negative classes) (r17663) +- Fix: Crash when an articulated RV is turning on a drive through road station that gets forcefully (bankrupt) removed [FS#3310] (r18049) +- Fix: GCC 4.5 compiling (r18045) +- Fix: AIs failed to load their data from savegames by crashing them when they tried [FS#3290] (r18038) +- Fix: Screen jumped a bit for at least SDL and Allegro when right-click-dragging (r18030) +- Fix: [NewGRF] Improve parsing of RIFF data. Skip unknown chunks and check chunk sizes (r17999) +- Fix: When you start giving money (input window for amount), then get moved to spectators and you click 'Ok' a crash would occur (r17953) +- Fix: Use 24bpp BMP format instead of 32bpp for screenshots. Saves space and is supported by more image viewers (r17943) +- Fix: Close BMP file when making screenshot fails (r17941) +- Fix: Deadlock when trying to create screenshot with too long name (including path) (r17936) +- Fix: Crash when closing NewGRF parameter window with no NewGRF selected [FS#3291] (r17922) +- Fix: 32bpp BMP screenshots were in wrong colours on big endian machines and broken when screen width was not a multiple of 4 (r17910, r17909) +- Fix: Uninitialised values in some paths of loading TTO savegames [FS#3288] (r17908) +- Fix: Make the plane speed setting unchangeable in network games because it can be read by NewGRFs on game load and thus if it changes cause desyncs (r17902) +- Fix: [NewGRF] 'subtract-in' is also signed for production callback version 0 (r17857) +- Fix: [NewGRF] _date_fract runs from 0 to 73 since r2041. Variable 0x09 should not (r17824) +- Fix: Do not fail hard when no soundcard could be detected; just fall back on the null-driver [FS#3268] (r17788) +- Fix: CJK languages do not have spaces, so for adding newlines (multi line strings) we need to (properly) handle the case when there are no spaces instead of truncating the string [FS#3264] (r17772) +- Fix: Powernaut Helicopter got wrong 'load amount' (r17758) +- Fix: [NewGRF] 'last_value' and 'reseed' are shared between procedure and main chain, 'scope' and 'count' are not (r17672) +- Fix: Count only active clients (not those waiting for map download) when checking min_active_clients limit (r16506) + + +0.7.3 (2009-10-01) +------------------------------------------------------------------------ +- Fix: [NewGRF] Crash when trying to build an industry that has no industry layout defined [FS#3233] (r17638, r17633) + + +0.7.3-RC2 (2009-09-24) +------------------------------------------------------------------------ +- Update: Documentation about bug reporting and known bugs (r17554) +- Fix: When a command did not fail in test run and failed in execution run, error message was not set. Affects only few commands (r17607) +- Fix: [NewGRF] Crash when defining the same tile in a tile layout twice [FS#3218] (r17605) +- Fix: Vehicle image was not always updated when needed (r17594) +- Fix: [NoAI] Could not query the size of small airports when they could not be build anymore [FS#3212] (r17591) +- Fix: Erroneous message about changing the difficulty level [FS#3220] (r17588) +- Fix: Assertion triggered when the second vehicle in a 101+ (or 11+ if mammoth trains is disabled) vehicle free wagon chain is an engine and the first vehicle is moved to another chain [FS#3208] (r17576) +- Fix: [NewGRF] Memory leak when viewing the NewGRF settings of a server (r17563) +- Fix: [NewGRF] The NewGRF settings of (remote) network games did not get properly updated when the NewGRFs were rescanned causing reading of freed data [FS#2972] (r17562) +- Fix: [NewGRF] Close the 'Add NewGRF' window when you close the 'NewGRF Settings' window. The add window has a pointer to the settings which means that not deleting it would cause dereferencing an already freed pointer [FS#3206] (r17559) +- Fix: Vehicles waiting for their time table did not load anymore after their initial load was completed [FS#3201] (r17551) +- Fix: Aircraft were given an unfair advantage in station rating calculations (r17550) +- Fix: [NewGRF] Sign extending of profit calculation did not work (r17546) +- Fix: [NoAI] AIs had 'infinite' time when running code from the global scope [FS#3202] (r17545) +- Fix: [NoAI] Crash when doing commands in the 'global' scope [FS#3202] (r17544) + + +0.7.3-RC1 (2009-09-13) +------------------------------------------------------------------------ +- Add: [NoAI] AITown::GetLastMonthTransportedPercentage and AIIndustry::GetLastMonthTransportedPercentage (r17294) +- Add: [NoAI] AICompany::Get/Set PresidentGender (r17016) +- Add: [NoAI] AIEngine::GetDesignDate (r17014) +- Add: [NoAI] AIStation::GetConstructionDate (r17012) +- Add: [NoAI] AIAbstractList::SORT_ASCENDING/SORT_DESCENDING (r17005) +- Change: [NoAI] AITown::GetLastMonthProduction now returns the same value as AITown::GetMaxProduction (r17293) +- Change: Mention the MD5 checksum of the original NewGRF in the 'saveload failed horribly'-error message and make it more clear that the filename is of the current NewGRF [FS#3139] (r17267) +- Change: Make overbuilding the front tile of a road station/depot with road consistent with overbuilding the front tile of tunnels/bridges [FS#2802] (r17239) +- Change: Improve error output on missing or corrupt files (r17238) +- Change: [Unix] Only use colourised error output on interactive terminals (r17227) +- Change: [NoAI] Crash an AI when it uses a DoCommand/Sleep instead of just printing an error message in the AI Debug Window [FS#2980] (r17223) +- Change: [NoAI] When the API requests a string as parameter allow every squirrel type and convert to a string [FS#3101] (r17221) +- Change: Make strgen warn if the translation uses STRINGn or RAW_STRING instead of STRING (r17137, r17129) +- Change: [NoAI] Load the API before compiling an AI script so AIs can subclass API classes and use API constants as part of their own constants (r17043) +- Change: Add notion of Ctrl+Click in the tooltip for Loan borrow/repay buttons [FS#3066] (r16979) +- Change: [MSVC] Make all language files depend on english.txt (r16975) +- Change: There is no point in not randomising engine introduction-date before 1922. Instead disable the randomisation for the first two years after game-start, so you do not have to wait for the first engine (r16929) +- Fix: [Squirrel] In some cases the call stack would not be cleaned up properly during crash handling. Occasionally this causes asserts to be triggered or crashes [FS#3189] (r17515) +- Fix: When loading GRFConfigs from ini file, validate them wrt. duplicate GRF IDs [FS#3197] (r17510) +- Fix: When building a part fails during cloning, sell what was already cloned instead of leaving it 'for free'. Also make cloning multiheaded trains possible with with 'max - 1' vehicles existing [FS#3196] (r17509) +- Fix: [NoAI] The wrong value was restored to SetAllowDoCommand possible resulting in an AI that was not allowed to do any actions (r17500) +- Fix: Road vehicles could get lost when the preliminary destination (for the pathfinder heuristics) is unreachable [FS#3188] (r17491) +- Fix: When building roads is not allowed for town, then do not build the initial piece either [FS#3173] (r17444) +- Fix: Destruction of depots did not remove any vehicle lists related to the depot, causing windows pointing to deleted depots and (thus) crashes [FS#3180] (r17442) +- Fix: Economy recession would never end when economy is set to Steady while in recession (r17426) +- Fix: The index of orders loaded from old savegames was overwritten with an uninitialised value (r17419) +- Fix: Incomplete check on validity of industry type when building industries (r17413) +- Fix: [Squirrel] Guard against Squirrel stack overflows (r17403) +- Fix: [NoAI] During every save a few slots on the Squirrel stack were leaked (r17402) +- Fix: [NoAI] Several AITile::* functions did not check whether their parameters were valid (r17378) +- Fix: Memory leak when trying to bankrupt the local company, other minor improvements of bankruptcy (r17342, r17341, r17340) +- Fix: Not all non-ASCII characters were entered with escapes in the About window (r17309) +- Fix: [NoAI] AIRail::RemoveRailTrack returned ERR_PRECONDITION_ERROR for road/rail-crossings (r17307) +- Fix: [NoAI] Reloading an AI started a new AI in the first available company slot causing other AIs to be started [FS#3153] (r17298) +- Fix: [NoAI] AITown::GetLastMonthTransported did not work as documented at all, make it return what AITown::GetLastMonthProduction did (r17293) +- Fix: Crash after upgrading base graphics set when opening the game options menu and you were using the upgraded set [FS#3147] (r17291) +- Fix: [Squirrel] Stack was not always cleared properly with tail recursion (r17284) +- Fix: [Squirrel] Calling a function that has default parameters with not enough parameters can cause a crash (r17273) +- Fix: Other tunnel end not shown if building rail tunnels and the first railtype is not available yet [FS#3141] (r17251) +- Fix: [NoAI] AIs that crashed during Save() were not killed as they should [FS#3134] (r17231) +- Fix: [NoAI] Do not assert when an AI uses AI*Mode objects incorrectly but crash the AI instead (r17230) +- Fix: Remove the (deprecated since 2006) Encoding entry from the openttd.desktop file (r17226) +- Fix: With time tables vehicles would stay in the 'loading' state after they have finished loading [FS#3129, FS#3130] (r17222) +- Fix: Do not ignore white space changes (e.g. alignment fixes) in the exporter (r17220) +- Fix: [NoAI] IsRoadTypeAvailable(GetCurrentRoadType()) was not a precondition for several AIRoad::* functions (r17203) +- Fix: [NoAI] Do not say you are building a depot when you are actually building a station (API docs typo) (r17201) +- Fix: Accept monthly production values in the scenario editor [FS#2406] (r17198) +- Fix: [Squirrel] FPE when an AI tried to do '% 0' (r17195) +- Fix: [NoAI] Guard the valuator against 'external' modifications of the valuated list which could cause it to go into an infinite loop [FS#3124] (r17193) +- Fix: Do not return exit value of rm, but of the actual configure run (r17163) +- Fix: A stuck train could free the reservation of another train if it was reversed or did crash (r17152) +- Fix: A train entering a PBS section through a block signal could cause a train crash if another reservation ending at a safe tile was already present in the section [FS#3104] (r17151) +- Fix: Update vehicle position cache when the vehicle sprite changes [FS#3060] (r17121) +- Fix: Mark industry tiles dirty when trigger are triggered (r17118) +- Fix: Squirrel_export.sh failed for some locales (r17109) +- Fix: Make restart command work again and make the help show how it works and how it does not work [FS#3092] (r17097) +- Fix: News message about ordered refits failing was not very clear [FS#3091] (r17096) +- Fix: Crash when renaming some stations [FS#3082] (r17078) +- Fix: RPM spec file failed for CentOS; apparently their rpmbuild is pickier or so [FS#3024] (r17077) +- Fix: [NewGRF] Mark house tiles dirty when triggers were triggered (r17047) +- Fix: [NewGRF] Trigger house trigger 02 only for the north tile [FS#3085] (r17046) +- Fix: Graphical glitch with graph key [FS#3083] (r17041) +- Fix: '[bd]ash'-ism in configure [FS#3076] (r17026) +- Fix: Infinite recursion in content dependency checking [FS#3075] (r17015) +- Fix: Concatenating strings in Squirrel when non-ASCII strings were received from OpenTTD failed [FS#3074] (r17013) +- Fix: [NoAI] Documentation of AITile::LevelTiles was wrong (r17049) +- Fix: [NoAI] AIBridge::GetPrice returned incorrect values (r16986) +- Fix: Make it so that failing to generate many random towns in scenario editor returns a failing message [FS#3059] (r16977) +- Fix: The last manually added server would not be saved [FS#3062] (r16981) + + +0.7.2 (2009-08-01) +------------------------------------------------------------------------ +- Fix: Vehicles would wait 'very long' when they had nothing to unload and gradual loading was disabled [FS#3054] (r16933) + + +0.7.2-RC2 (2009-07-21) +------------------------------------------------------------------------ +- Fix: When marking trains stuck do not reset the unload/stuck counter when the vehicle is unloading. It will be automatically reset once the vehicle wants to leave the station [FS#3038] (r16901) +- Fix: [NoAI] Small errors in the API documentation [FS#3037] (r16865) +- Fix: Savegames from before 0.4 would get their waypoint 'index' messed up (r16854) +- Fix: Cargo payments were not destroyed when a vehicle was destructed. This only happened when you crashed a vehicle while it was unloading [FS#3032, FS#3046] (r16801) + + +0.7.2-RC1 (2009-07-15) +------------------------------------------------------------------------ +- Add: Plural 'rule' for Korean (r16811) +- Add: [NoAI] AIVehicle::GetReliability to get the current reliability of vehicles (r16790) +- Fix: Call the AI Save() function only once so AIs can not crash OpenTTD [FS#3034] (r16834) +- Fix: Use the palette of the vehicle being drawn instead of the one of the front vehicle (r16819) +- Fix: Automatic resizing of SelectCompanyLiveryWindow was not working as expected [FS#3021] (r16809) +- Fix: Service orders did not behave like conditional orders; if a train does not need service it did not completely skip the order, but still go in the direction of the depot [FS#3031] (r16802) +- Fix: Houses would not get build on the map edge [FS#3025] (r16795) +- Fix: Audio playback rate was fixed at 11025Hz regardless of the rate specified to the audio driver, resulting in incorrect playback speed. It is still preferable to use 11025Hz output rate if possible as OpenTTD's sample rate converter is very low quality (r16784) +- Fix: Do not use the same error message for turning around road vehicles and flipping parts of trains in the depot [FS#3019] (r16772) +- Fix: [Windows] The binary packages would not get their readme converted to DOS line endings (r16769) +- Fix: [NoAI] AITile::GetCargoProduction/Acceptance did not accept a radius of 0 anymore (r16767) +- Fix: In the refit window the 'Select cargo type to carry' line always showed the ship refit tooltip [FS#3018] (r16757) +- Fix: When loading a savegame Engine::grffile might be left NULL in certain cases (dynamic_engines enabled, articulated vehicle with only wagon-override action3s) (r16737) +- Fix: Show Close instead of Cancel when there is nothing to cancel in the content downloading window [FS#2991] (r16732) +- Fix: [NoAI] AIDepotList contained wrong tiles for hangars when st->xy != st->airport_tile (r16731) +- Fix: The Join station window did not show all stations nearby in some cases (r16728) +- Fix: Invalidate subsidies with invalid source or destination when converting older savegames (r16710) +- Fix: The list of animated tiles could have duplicates (only for old savegames) and tiles that were not animated [FS#2994] (r16709) +- Fix: When SDL/Allegro fail to initialise, fall back on another video driver but not to the null driver (r16702, r16700, r16699) +- Fix: Limit the screen's resolution to 65535x65535 so the dirty pixels stay within bounds of a 32 bits integer [FS#3001] (r16701) +- Fix: Only pay for whatever has been actually unloaded and perform the payment when unloading has finished [FS#2995] (r16694) +- Fix: Missing debug string for ESRB_SAFE_TILE in YAPF debugging helper [FS#3002] (r16690) +- Fix: When there is no AI version that can load data from the savegame, load the latest version of the same AI instead of a random AI (r16651, r16650, r16649) +- Fix: Loading of some town data from old savegames was broken (r16631) +- Fix: [NewGRF] Some of the var action 2 80+ variables contained wrong results from NewGRF perspective (r16615, r16613) +- Fix: Antialiased fonts broken; check pixel_mode instead of palette_mode (r16602) +- Fix: Give a more meaningful error message when console commands expect an integer but do not get one (r16600) +- Fix: Mouse would under some circumstances not be undrawn when drawing the first chat line causing two mouse pointers to be visible [FS#2969] (r16594) +- Fix: Do not crash when tars/NewGRFs are removed, just tell the file could not be opened/found [FS#2967] (r16590) +- Fix: Set default stack size to 1MB to prevent _chstk crash (MSVC) [FS#2978] (r16589, r16588) +- Fix: [Network] Always send the starting date from the game you are currently playing instead the starting date from the config file (r16573) +- Fix: Also catch FPEs in saveload and the warning about missing NewGRFs; only happens when assertions are disabled and NewGRFs are missing (r16572) +- Fix: In some cases, train could be stuck in depot [FS#2974] (r16571) +- Fix: [NoAI] AIMarine::AreWaterTilesConnected did not return true for bridge head<>neighbouring water tile (r16563) +- Fix: Removing of duplicates of base graphics set could behave randomly (r16548) + + +0.7.1 (2009-06-09) +------------------------------------------------------------------------ +- Fix: When finding duplicate graphics sets favour the more complete one (r16538) +- Fix: [Squirrel] Crash that occurred when an AI was halted while one or more generators were still in a 'running' state [FS#2942] (r16534) +- Fix: [Squirrel] Do not copy an object when we just checked that the pointer to it is NULL (r16532) +- Fix: Notify small UFOs on deletion of road vehicles, so they can head for somewhere else instead of stumbling over a ghost (r16525) +- Fix: [NoAI] StationIDs from oilrigs were not considered valid by the API (r16529) +- Fix: Draw PBS reservation as groundsprite resp. childsprite of foundation/bridgehead [FS#2959] (r16528) +- Fix: Missing guards in the NoAI API making it possible to hit an assert in OpenTTD [FS#2963] (r16524) +- Fix: [NoAI] Possible assert in AI debug window when an AI was stopped and a human company took its CompanyID [FS#2962] (r16522) +- Fix: [NoAI] Make sure AIBridge::BuildBridge returns what the documentation says it does (r16520) + + +0.7.1-RC3 (2009-06-03) +------------------------------------------------------------------------ +- Add: [NoAI] AISignList that can be used to get a list of valid signs (r16400) +- Change: [NoAI] Stop an AI when it takes too long to initialise or load [FS#2869] (r16425) +- Fix: Base graphics names must be unique, so do not add duplicates (r16503) +- Fix: [NoAI] When an AI was suspended while in a function called (indirectly) via call/acall/pcall OpenTTD crashed. Fix this by disallowing AIs to be suspended while called via call/acall/pcall [FS#2935] (r16502) +- Fix: [NewGRF] Invalidate NewGRF variable caches of more vehicles in more places. Esp. they were only invalidated for trains (r16480) +- Fix: [NewGRF] Call callbacks after initialisation of vehicle variables (r16479) +- Fix: [NewGRF] Determining most common (sub-)cargo-type was broken due to someone confusing similarly named variables (r16478) +- Fix: Loading indicator when 'unload' in and 'no loading' is off was pointing in the wrong direction [FS#2936] (r16477) +- Fix: Track reservation was drawn at bridge heads in the menu (r16470) +- Fix: [NoAI] Another try/catch related bug (r16454) +- Fix: Road vehicles ending up on the pavement when they are in a drive through station that got removed due to bankruptcy [FS#2909] (r16448) +- Fix: [NoAI] AIRail::GetRailStationDirection returned incorrect information (r16440) +- Fix: Crash when a company is deleted while a dropdown with company names is open (r16430) +- Fix: Do not allow content download via the console when there is no zlib as it is done for the GUI already [FS#2919] (r16420) +- Fix: Some 64bit architectures require size_t to be aligned at 8-byte boundary, ensure it for MemBlock (r16415) +- Fix: [NewGRF] Disable multitile houses with non-zero population on additional tiles as they cause desyncs and because the specs do not allow that either (r16383) +- Fix: [NewGRF] Valid UTF-8 sequences between 0x20 and 0xFF should be allowed as is instead of being treated as control codes (r16374) +- Fix: [NewGRF] Use a valid StringID as fall-back when undefined generic NewGRF strings of vehicles are requested (r16366) + + +0.7.1-RC2 (2009-05-21) +------------------------------------------------------------------------ +- Fix: The previously selected NewGRF station type was still remembered after switching to a different game without newstations enabled, preventing stations from being built (r16363) +- Fix: Pointer incremented with wrong count (r16361) +- Fix: Delete invalid depots in TTD savegames caused by improper SVXConverter conversions (r16357) +- Fix: Invalid read when OpenTTD savegame contains VEH_INVALID (r16353) +- Fix: Signal handler could end in endless loop (r16351) +- Fix: [NewGRF] When overriding 'original sounds', only allow overriding of the 'original sounds' and not any other that is already loaded (r16339) +- Fix: Desyncs when removing lots of stations/towns (r16329, r16328) +- Fix: Desyncs due to the fact that depot searching with a maximum search depth simply does not work with YAPF's caches [FS#2900] (r16323) +- Fix: Trains could get stuck in a depot when they wanted to go to the same depot again [FS#2873] (r16322) +- Fix: In the scenario editor change the (starting) game year of the scenario, not the (starting) game year for new games/scenarios (r16321) +- Fix: Loading of savegames created in revision between 0.3.5 and 0.3.6 caused crash (r16320) +- Fix: [NoAI] Set the autorenew settings for new AI companies to the default values, not to 0 or the local settings (r16316) +- Fix: [NewGRF] Allow accessing the house age when the house is not yet built (r16314) +- Fix: (Get|Set)TrackBits() is only valid for RAIL_TILE_NORMAL and _SIGNALS (r16311) +- Fix: Parameter is invalid when it is equal to length of an array (r16308) +- Fix: Close all windows before unloading the AI system as closing the content-download window will rescan for AIs [FS#2901] (r16306) +- Fix: ICC (Intel C++ Compiler) defined __GNUC__ but does not define __builtin_bswap32, so fall back to the default swap method for ICC (r16295) +- Fix: Road vehicles were unable to find a depot when turning around (in some cases), causing 'nearest depot' orders to be occasionally lost [FS#2893] (r16291 +- Fix: Unable to (re)set the desert state for watery tiles [FS#2888] (r16290) +- Fix: Possible (in theory) desync related to autorenew settings (r16287) +- Fix: Crash after using the 'Reset landscape' function and remove all waypoint signs and buoys after resetting landscape (r16280) +- Fix: [NewGRF] Disable multitile houses for which the NewGRF does not define proper additional tiles (r16274) + + +0.7.1-RC1 (2009-05-11) +------------------------------------------------------------------------ +- Add: [NoAI] AIController::GetVersion, this returns the version of OpenTTD in the same way as for NewGRFs (r16253) +- Add: [NoAI] AIAirport::GetPrice, returning the building cost of an airport (r16252) +- Add: [NoAI] Two new error codes to AITile: ERR_AREA_ALREADY_FLAT and ERR_EXCAVATION_WOULD_DAMAGE (r16171) +- Add: [NoAI] AITile::Get(Min|Max|Corner)Height (r16166) +- Add: [NoAI] Several functions to AIOrder to check the what kind of order an order is and AIVehicle.SendVehicleToDepotForServicing [FS#2801] (r16165) +- Add: [NoAI] UseAsRandomAI as function in info.nut. When an AI returns false, it will never be chosen as random AI (r16113) +- Add: [NoAI] AIOF_STOP_IN_DEPOT to the orderflags in AIOrder to allow stop-in-depot orders (r16107) +- Add: [NoAI] GetURL() as possible function to info.nut. If AIs implement it, that url is shown when the AI crashes and also in the AI selection window [FS#2808] (r16093) +- Change: [NoAI] Reverse the order of the lines in the AI debug window [FS#2778] (r16091) +- Change: Harden string copying on places where it is possible (r16024) +- Change: Use recent Czech language for plural form (r15965) +- Fix: Wrong number of parameters or wrong parameter types sent to printf-like functions at several places (r16269) +- Fix: [NewGRF] When callback 2E returns an amount of 0, do not transport 1 unit to the station (r16268) +- Fix: [NoAI] Various documentation omissions with respect to IDs of various objects and corners for AITile::(Raise|Lower)Tile (r16267, r16266) +- Fix: [NoAI] Check slopes passed to the API better for validity (r16264, r16262) +- Fix: [NewGRF] Interpret setting bridge property 08 to 0 as always available (r16263) +- Fix: [NoAI] Enable parameter checking for AIController::* functions again (r16249) +- Fix: [NoAI] Make sure AITunnel::BuildTunnel returns what the documentation says it does (r16244) +- Fix: [NoAI] CmdBuildTunnel could be called with invalid parameters from the API code, causing crashes later [FS#2875] (r16243) +- Fix: Improve corner case order handling: mark order as done only when actually done, obey non-stop orders, do only stop/refit at the depot in the order (r16240, r16228, r16199, r16198, r16187) +- Fix: [NoAI] Use the stop/non-stop intermediate orderflags AIs can give for goto-depot orders (r16239) +- Fix: [NewGRF] ActionB should use the online parameters from GRFFile instead of the initial user-specified values from GRFConfig. Also use the values as they were set when the ActionB was executed, not as they are set when the message is shown (r16223) +- Fix: Possible crashes when quiting OpenTTD or forcing resizes/redraws of the screen during map generation [FS#2862] (r16220) +- Fix: Shared orders without orders were not properly converted causing corrupt/invalid orders when loading pre 0.7 savegames [FS#2878] (r16214) +- Fix: Hardcoded (old sized) MAX_COMPANIES constant (r16182) +- Fix: [Squirrel] The traps variable was not restored, causing try/catch blocks to be 'forgotten' during a suspend (r16181) +- Fix: Do not try to reserve path for trains crashed in station [FS#2866] (r16178) +- Fix: Forbid joining AI companies via the 'move' and 'join' console commands/multiplayer lobby (r16176, r16175) +- Fix: [NoAI] AIOrder::GetOrderDestination and AIOrder::GetOrderFlags did not work on ORDER_CURRENT when the vehicle was loading/leaving in a station (r16165) +- Fix: [NoAI] Change WAYPOINT_INVALID to 0xFFFF from -1 as that is the value the AIs got (due to casting) (r16150) +- Fix: The overflowsafe type did not like dividing by int64 larger than MAX_INT32 causing division by negative numbers and small anomolies when drawing graphs [FS#2855] (r16130) +- Fix: Road was removed when both the Remove button was active and Ctrl was pressed [FS#2582] (r16119) +- Fix: [NoAI] Make sure AIOrder::GetDestination always returns a tile belonging to the station (16109) +- Fix: [NoAI] When giving an aircraft a goto-hangar order do not let it be a normal goto-station order (r16108) +- Fix: [NoAI] AIOrder::SetOrderFlags always removed 'Service if needed' from goto-depot orders (r16106) +- Fix: Connect tried to validate too much of the company ID with too little information on hand [FS#2849] (r16096) +- Fix: [NoAI] AIDebug window profiled the blitters by invalidating itself unconditionally on repaint. On the other hand it was not invalidated in other cases when needed (r16094) +- Fix: The language is called Slovak, not Slovakish (r16090) +- Fix: Insanely fast trains would not stop in time for stations/'jump' over waypoints/via stations within a tick, which would cause the order not to be processed causing the train to go in loops until (with luck) it 'hit' the tile [FS#2824] (r16079) +- Fix: Content download progress bar 'resetting' due to mathematical overflow [FS#2845] (r16071) +- Fix: Memory leak when querying a server multiple times (r16064) +- Fix: [NoAI] MOF_COND_DESTINATION was not accepted by CmdModifyOrder() (r16063) +- Fix: Non advanced vehicle list did not handle company switching correctly (r16054) +- Fix: Do not warn that crashed vehicles are getting old; upgrading them is impossible [FS#2740] (r16048) +- Fix: The currency abbreviation for the Romanian Leu is now RON [FS#774] (r16041) +- Fix: Dash was not able to run iconv detection (r16035) +- Fix: [NewGRF] Do not give '... Mines' as name to the station of oil rigs, or more general: do not add '... Mines' when the all of the cargoes are part of the liquid, passenger or mail classes [FS#2785] (r16029) +- Fix: Storing/loading some currencies failed due to inconsistent settings 'tables' [FS#2826] (r16028) +- Fix: Usage of uninitialised memory when trying to build a random new industry, but there are no industrytypes to choose from (i.e. all appearance probabilities are zero) (r16027) +- Fix: 'Build separate station' in the station picker would reuse deleted stations [FS#2818] (r16025) +- Fix: 32 bpp sprites in tars would also be shown in the list of heightmaps [FS#2817] (r16023) +- Fix: Sometimes the unregister 'query' thread could be delayed so much that the network stuff was already closed and the packet would never reach the master server causing the server to appear online longer than necessary (r16022) +- Fix: Chance16() did not work for b = 1. Also transform the formula to not use divisions (r16006) +- Fix: Inconsistency between using NETWORK_NAME_LENGTH and NETWORK_CLIENT_NAME_LENGTH for the length of client names (r15988) +- Fix: [NewGRF] Abort production callback after 0x10000 iterations and show a messagebox blaming the NewGRF [FS#2787] (r15958) +- Fix: [NewGRF] Set callback_param1 (var 10) to 1 only when requested (r15957) +- Fix: Tooltip of detailed ratings window button showed wrong message (r15943) + + +0.7.0 (2009-04-01) +------------------------------------------------------------------------ +- Feature: Watermark crash.sav and do not generate crash information if a loaded crash.sav causes a crash so the real crash report does not get overwritten (r15893) +- Feature: Add autoclean_novehicles setting which will, when autoclean_companies is true, remove any company with no vehicles and no active client after autoclean_novehicles-months (r15848) +- Add: [NoAI] AIIndustryType::IsBuiltOnWater(), HasHeliport() and HasDock(). Just like AIIndustry (r15901) +- Add: [NoAI] AIBridge::GetBridgeID() so AIs can get the type of bridge that are already build (r15875) +- Add: [NoAI] AIRoad::GetRoadVehicleTypeForCargo() to tell whether a certain cargo needs a bus- or a truckstop (r15860) +- Fix: Chat completion got called twice causing tab completion to seemingly fail (r15905) +- Fix: YAPF did not apply the platform length (too long/too short) penalties (r15900) +- Fix: Fixing the slopes was done a bit more often than intended making map generation with the original generator horribly slow (r15895) +- Fix: YAPF used different penalties for aqueducts than for other water tiles (r15891) +- Fix: Round the production rate up, so e.g. oilrigs always produce some passengers on lowest production level [FS#2772] (r15888) +- Fix: Libtimidity cannot handle frees of NULL (in contrast of most other frees) [FS#2770] (r15886) +- Fix: Make sure house class/ID counters do not overflow (r15831) + + +0.7.0-RC2 (2009-03-23) +------------------------------------------------------------------------ +- Change: [NewGRF] Expose GRF ID of engines in var action property 0x25 (r15739) +- Fix: Some (newer) GCCs have trouble compiling the Windows specific part of fontcache.cpp; jumps across variable declarations [FS#2752] (r15818) +- Fix: When sorting on cost do not sort on the running cost [FS#2749] (r15778) +- Fix: Do not show the message about reporting an AI crash for the dummy AI (r15774) +- Fix: Number of active clients was not always properly updated [FS#2475] (r15773) +- Fix: Settings from the [gameopt] section (from old 0.6 config files) were overwritten with default values (r15771) +- Fix: Infinite loop when skipping sprites when a GRF is invalid (or truncated) (r15767) +- Fix: Crash when opening the content list window twice; inconsistencies when clicking download twice [FS#2744] (r15766) +- Fix: Add Engine::GetDisplayDefaultCapacity() and use it everywhere, so CB 36 is also used everywhere (r15763) +- Fix: [Windows] Inlined UTF-8 characters (in the source code) are not handled properly on Eastern versions of Windows so escape them (r15762) +- Fix: [Windows] On some system searching a font using its English name fails. So now we search the font using the localised name and use the English name for the final 'validation' only (r15757) +- Fix: Number of houses in house variables 0x44, 0x60 and 0x61 were incorrect after 0xFF had been reached and could desync clients joining afterwards (r15755) +- Fix: Crash when clicking the small area between the savegame list and the save button in the save game window [FS#2742] (r15753) +- Fix: Do not try to (un)draw the cursor when the screen is not ready (r15752) +- Fix: The big UFO sometimes landed just outside the map. Instead of landing, just disappear (fly away) in those cases (r15750) +- Fix: Crash because submarines would sometimes start far outside of the map [FS#2739] (r15748) +- Fix: Road ownership getting lost when removing a road stop [FS#2736] (r15747) +- Fix: Update threading code for OS/2, add mutex support, fix compilation (r15746, r15745) +- Fix: When town generator failed to create requested number of towns, there were too many cities (r15744) + + +0.7.0-RC1 (2009-03-16) +------------------------------------------------------------------------ +- Feature: Pop up the AI Debug Window if one of the AIs crashed and show a message that the user should report the crash [FS#2728] (r15708) +- Feature: Allow the number of towns that will be generated in the generate world window to be customised [FS#2672] (r15695) +- Fix: Enabling freeform edges could cause submarines to get stuck on land tiles (r15733) +- Fix: Centring on a vehicle did not respect its z coordinate (r15725) +- Fix: Do not show passenger-/mail-capacity if the aircraft carries only cargo (r15705) +- Fix: Blame NewGRFs returning inconsistent information in purchase-list/after building before users have a chance to blame OpenTTD for incorrectly autorenewing/-replacing [FS#2595] (r15701) +- Fix: Just sell the old engines after autorenew/replace. Do not bother about trains exceeding the trainlimit, which will be sold anyway [FS#2721] (r15692) +- Fix: Do not crash when the generate map does not contain a suitable location for a town [FS#2720] (r15689) +- Fix: Do not crash when someone substitutes the 'map generation' sprites with garbage [FS#2720] (r15685) +- Fix: Vehicle images would be determined during the process of moving the vehicle which means that only the (orientation) data for the vehicles in front of it is valid. Now the data for the vehicles behind the vehicle are valid too [FS#2546] (r15677) +- Fix: It was possible to remove rail tunnels/bridges and aqueducts build by rival companies [FS#2718] (r15667) +- Fix: Sorting of engines in the purchase list did not use the same numbers as the GUI showed, e.g. articulated parts were not taken into account when ordering by capacity [FS#2689] (r15666) +- Fix: Handling of aircraft crash counter did not take account of the reduced number of calls (from 6 down to 2) to the aircraft event handler, resulting in crashed aircraft taking three times longer than they should to clear. Compensate by increasing the counter by 3 on every call instead of 1 (r15665) +- Fix: Growing of vsize as (some) threads were not properly released (r15663) +- Fix: Do not mark a company as having ratings in a town when querying the cost of a command (r15662) + + +0.7.0-beta2 (2009-03-10) +------------------------------------------------------------------------ +- Feature: Allow downloading scenarios and heightmaps via the in game content download (r15632) +- Feature: When cloning a vehicle with a custom name, add and/or increment a number at the end of name and assign it to the new vehicle (r15621) +- Feature: Show scenarios/heightmaps from both your home directory and installation directory (r15615) +- Feature: Allow building road stops on road/tram tracks of competitors (r15601) +- Feature: Show required/already-delivered cargo needed for town-growth in town-view-window and only if it is really needed (r15559) +- Feature: [NewGRF] Support vehicle vars 0x47 and 0xF2 in purchase list (r15542) +- Feature: [NewGRF] Show the cargo subtype in the vehicle details window (r15480) +- Change: The background of the the waypoint sign is now in the company colour (r15593) +- Change: Allow the default debug level of 6 for a dedicated server to be overridden by -d (if used after -D) (r15543) +- Change: [NewGRF] To decide whether a vehicle is refittable do not test its current capacity for being zero, but always use the 'capacity property' (r15541) +- Fix: [Squirrel] Almost infinite loop in garbage collection (r15659) +- Fix: Undeterministic file sorting when the date is equal for all files [FS#2716] (r15657) +- Fix: Changing vehicle.dynamic_engines when there are already vehicles can cause crashes (r15656, r15586) +- Fix: Only ever call any vehicle callbacks after the whole articulated engine has been built (except 0x16) (r15654) +- Fix: C++'s new (this) is seldom a good idea as destructors of member variables are not run causing memory leaks [FS#2706] (r15652) +- Fix: [OSX] Hack around an OSX stupidity in < 10.4 w.r.t. signals by not having any signal handling support for OSX < 10.4 (r15648) +- Fix: Add an EngineOverrideManager to give the term 'compatible NewGRF' again some sense and to not crash because of trivial changes [FS#2612] (r15645) +- Fix: Closing a network connection twice in the case that sending packets starts failing while disconnecting [FS#2710] (r15644) +- Fix: Game crashes when network pools are empty, so always allocate at least one pool block [FS#2712] (r15641) +- Fix: Do not allow more than 64 road vehicles to reserve a slot at a single road stop. 255 + 1 gives trouble, but 64 is even more than the road stop would be able to handle within the slot timeout time [FS#2707] (r15635) +- Fix: Kicking/banning a client from the Client list window crashed the server [FS#2705] (r15628) +- Fix: UTF8 string handling could cause buffer overruns [FS#2698] (r15626) +- Fix: When trying to reserve a self-crossing path the failed reservation was sometimes not cleared completely [FS#2701] (r15619) +- Fix: Towns would only build houses where the grid would not be, even when they are not allowed to build roads and the user 'implements' another layout [FS#2661] (r15604) +- Fix: Crash when using an extraordinarily large sprite as cursor [FS#2696] (r15601) +- Fix: Crash when opening viewport while scrolling the map and the mouse 'lands' on the window decoration of the viewport [FS#2695] (r15598) +- Fix: [NewGRF] Refit-info in purchase list did only check the first articulated part (r15592) +- Fix: Change owner of waypoints and deleted stations when merging companies or when a company bankrupts (r15588) +- Fix: Last activity time not properly updated causing downloads to be aborted after a minute [FS#2684] (r15580) +- Fix: Force unload not working when trying to force unload at the station where you received the cargo [FS#2680] (r15574) +- Fix: Theoretical buffer overflow when a company with too long name funded a road reconstruction (r15572) +- Fix: When building signals by dragging from a pre/entry/combo block signal, the signal you started at became a normal block signal [FS#2674] (r15567) +- Fix: Dependency information was not requested after the content state was reset causing the dependencies not always being selected (and thus downloaded) automatically [FS#2675] (r15565) +- Fix: Crash when saving a preset with unknown NewGRFs [FS#2646] (r15561) +- Fix: The font width cache was not updated when changing fonts causing the font spacing to be off when changing fonts in-game (auto font detection) (r15557) +- Fix: -v null crashing in 2051 due to trying to show the high score of the spectator (r15554) +- Fix: [NoAI] Crash when setting a depot order to the southern part of a ship depot [FS#2656] (r15551) +- Fix: The keep_all_autosave setting was ignored for dedicated servers/spectators [FS#2651] (r15546) +- Fix: If a buoy was placed directly in front of a dock, that dock was seen as a buoy and thus skipped once within 3 tiles [FS#2653] (r15545) +- Fix: Extracting downloaded content did not work for Windows if one uses a non-ASCII path [FS#2650] (r15544) +- Fix: [NewGRF] When articulated parts have no available default cargo, use the cargo type of the first part for livery selection [FS#2617] (r15541) +- Fix: Testing of 'only_this' in CmdRefitRoadVeh() could be skipped by 'continue' (r15540) +- Fix: [NewGRF] If an aircraft cannot carry any available cargo, it should not be available either instead of falling back to passenger/mail. Just like the other vehicle types also do (r15539) +- Fix: Do not allow special sprite characters (e.g. the ship sprite) as characters in input like filenames or text that is sent over the network (r15537) +- Fix: The local command queue did not get properly cleaned when leaving a game meaning you could end up executing commands of the previous network game [FS#2644] (r15529) +- Fix: Do not try to find the AIs the server runs when joining a multiplayer server (r15525) +- Fix: Use distance to closest station tile as estimate for YAPF too (NPF already does so). This makes it behave 'better' with wide stations [FS#2631] (r15518) +- Fix: [NewGRF] Wagonoverrides and articulated engine parts use the colour scheme of the engine, but not its recolour callback, nor its 2CC flag. Same applies to roadvehicles [FS#2642] (r15517) +- Fix: [NewGRF] Livery overrides for articulated parts of roadvehicles were not applied (r15516) +- Fix: Make the join/spectate command require to be connected to a network game; in SP it could lead to crashes (r15514) +- Fix: Generating a map with the original map generator with freeform edges on resulted in a crash [FS#2641] (r15511) +- Fix: Pre-0.5 OpenTTD stored new_nonstop and full_load_any in a different way, savegame conversion was not working for them (r15500) +- Fix: Crash when opening the game options when the currently loaded base graphics pack has less than 2 valid graphics files. For example when someone replaces all his/her original base graphics with custom work (but keeps the name) or renames the dos ones to windows or vice versa [FS#2630] (r15476) + + +0.7.0-beta1 (2009-02-16) +------------------------------------------------------------------------ +- Feature: Make it possible to have multiple windows with edit box open simultaneously (r15424) +- Feature: Add ability to select which base graphics set is used from the Game Options window. The change takes effect when the window is closed. This option can only be used from the intro menu, as reloading graphics during a game may cause issues (r15389) +- Feature: Do not draw superfluous catenary wires [FS#1761] (r15347) +- Feature: Add option to group and subtotal expenses list in the company finance window (r15301) +- Feature: Allow moving clients between companies/spectators by the server and the clients themselves (r15242) +- Feature: Native support for Transport Tycoon (Original) savegames (r15216) +- Feature: Allow terraforming of the tiles at the edges of the map (r15190) +- Feature: [NewGRF] Allow a grf to customise house name via callback 0x14D, during Tile Inquiry process (r15172) +- Feature: Downloading content from a central server (content.openttd.org) where authors can upload their NewGRFS/AI etc. This should make joining servers that use only NewGRFs that are distributed via this system easier as the players can download the NewGRFs from within the game. It should also make it easier to see whether there are updates for NewGRFs and make the necessary updates (r15126) +- Feature: Add support for IP range bans using CIDR notation (r15094) +- Feature: An AI framework so people can write their own AIs. This also removes the old cheating and heavily broken AI (r15027) +- Feature: [NewGRF] Support var 0x45 (curvature info) also for road vehicles (r14945) +- Feature: [NewGRF] Automatically set last engine ageing year to the last 'introduction year plus half model life', to allow engines later than 2050 to appear (r14926) +- Feature: Distant joining of stations (r14919) +- Feature: Advanced setting to keep various building tools active, which are usually closed after placing an object (r14902) +- Feature: Remove the window limit, but leave a configurable limit on the number of non-sticky non-vital windows (r14899) +- Feature: Allow road vehicles to move multiple steps in a tick (code based on train movement code) and add support for RV prop 15. This gives RVs a maximum speed of 318mph instead 79mph. This only implements higher speeds, not 'realistic acceleration' (r14869) +- Feature: Automatic reversing in front of block signals can now be disabled by setting pf.wait_oneway_signal respectively pf.wait_twoway_signal to 255 (r14852) +- Feature: Few (optional) optimisations to making (initial) orders; like keeping goto selected [FS#1984] (r14827) +- Feature: Make the road grids of town match, when all are using the same road layout of course [FS#2390] (r14821) +- Feature: Pressing CTRL while dragging to build a bridge builds the last built bridge type if possible [FS#2238] (r14805) +- Feature: Make the date format for default savegame/screenshot names configurable (r14792) +- Feature: Allow scrolling with the left mouse button pressed (if enabled). Primarily useful for systems with touch screen (r14789) +- Feature: Allow up to 15 companies (r14735) +- Feature: Allow up to 255 clients in multiplayer games (r14730) +- Feature: When the chosen language is not supported by the current font, try to find a font that does and use that instead (r14618) +- Feature: [NewGRF] Action0Industries property 24 (industry supplies default name for nearby station) (r14598) +- Feature: Non-destructive autofill with option to keep waiting times [FS#1124] (r14592) +- Feature: Stop-in-depot order; after this order you have to manually start the vehicle again (or sell it) (r14524) +- Feature: Arrow key scrolling in the server list (r14517) +- Feature: Initial support for handling bidirectional scripts and connecting Arabic characters (r14479) +- Feature: Allow sorting vehicles by remaining life time (r14352) +- Feature: Ability to reset name to default/automatic value (for vehicles, engines, towns, groups, stations, waypoints, managers and companies) (r14334) +- Feature: [NewGRF] Add Variational Action 2 Variable 0x47 for houses, Coordinates of the house tile (r14294) +- Feature: Allow overriding the palette of the base GRFs. This way you can play with NewGRFs made for the Windows palette with the DOS palettes base GRFs (and vice versa). Note that for this to work correctly ALL NewGRFs must use the same palette; mix and match is not yet supported (r14229) +- Feature: Double click to join selected server/company (r14209) +- Feature: Allow both the German as well as non-German toyland graphics as 'correct' and official graphics (r14197) +- Feature: Allow people to create their own base graphics easily and without requiring code changes (r14197) +- Feature: [NewGRF] Add support for property 0x13 for Bridges. In other words, one can now specifies a 16 bits cost multiplier (r14172) +- Feature: Make it possible to choose between the DOS and Windows graphics packs while retaining the possibility to override the palette (r14151) +- Feature: Increase the size of the console backlog. Now it'll only remove backlog items when there are more than a threshold and when they are there longer than (another) threshold (r14056) +- Feature: Make it possible to filter list_patches output like it is done for other list_* console commands (r14041) +- Feature: Path based signalling (r13926-13967) +- Feature: Show [total-]cargo info in depot when [ctrl-]right-clicking on vehicle (r13923) +- Feature: NewGRF presets, selected by a drop down list in the NewGRF window. Presets are saved in the config file (r13781) +- Feature: Add a few extra columns with information to the server list (r13732) +- Feature: [NewGRF] Add var 65 in Variational Action 2 Variables for Houses (r13603) +- Feature: [NewGRF] Implement var 63, variational action2 variable for Houses. Or, in more simple terms, the check for the animation frame of nearby house (r13519) +- Feature: Aqueducts (r13464) +- Feature: [NewGRF] Add var 0x69 for industries, long format construction date (r13443) +- Feature: [NewGRF] Add long format introduction and maximum construction year for house (r13437) +- Feature: [NewGRF] Add access to current long year and date from Action 7/9/D and VarAction2 (23/24 or A3/A4), and add access to (long format) building year, in Variational Action2 Variable 49 for Vehicles (r13376) +- Feature: Splitting of the main toolbar when the resolution becomes very low so the buttons are still visible and usable (r13339) +- Feature: Make news messages use a linked list instead of a moving circular buffer. This makes it possible to store more news messages in the history (r13317) +- Feature: The number of news messages is reduced by removing every news message that is a configurable amount older than when it would not be shown in the newspaper popup/ticker, which is e.g. a month for industry production changes and half a year for subsidy offers. As a result the more important messages will stay longer in the message history (if longer than 30 messages) (r13317) +- Feature: Allow to have more than only two airports per town. The number of airports is now controlled by the noise each of them generates, the distance from town's centre and how tolerant the town is (13226) +- Feature: Introducing the so called 'engine pool' which primarily removes the fixed engine type limits and also happens to allow (with the patch option 'dynamic_engines') multiple NewGRF vehicle sets to coexist (r12924) +- Feature: [NewGRF] The ability to play NewGRF sounds for industries and stations (r12817) +- Feature: [NewGRF] Add some support for NewGRF station animation (r12798) +- Feature: Sorting vehicle lists by road vehicle/train length (r12766) +- Feature: Conditional 'skip/jump' orders (r12667) +- Feature: Ability to send a vehicle (using default orders) to the nearest depot (r12661) +- Feature: Ability to force a vehicle to not load or to not unload at a station (r12650) +- Feature: Four different non-stop types, individually selectable per order. Replaces 'TTDP compatible order' setting (r12648) +- Feature: Three different load type in a single game instead of two. One can choose full load all and full load any instead of full load being governed by the 'full load any' patch setting (r12648) +- Feature: Financial and Player Selection Face windows are now remembering their position when toggling sizes (r12634) +- Feature: Show what cargoes a station could be supplied with (r12596) +- Feature: [NewGRF] Add random action 2 type 84. For vehicles only (r12452) +- Feature: [NewGRF] Add support for var A2/22 for action 7/9/D: Difficulty level (r12449) +- Feature: Add +/- toggle buttons to station cargo waiting list to show/hide the detailed transferred cargo information (r12446) +- Feature: Open the time table when pressing the order button while pressing the CTRL key (r12441) +- Feature: On Screen Keyboard for input fields so someone without a keyboard can enter text too [FS#1846] (r12425) +- Change: When checking for unique names, compare only with manually set names [FS#1923] (r14958) +- Change: Apply the 'warn if train's income is negative' setting to other vehicle types, too (r14835) +- Change: When loading games in 'network' mode use the start date of the save game for the server and all clients when loading the NewGRFs instead of the current date. Prevents desyncs caused by action 7/9s skipping parts of the GRF based on the date or some other variables that can differ at NewGRF load time (r14769) +- Change: Only say a engine/vehicle is refittable when it can be refitted to at least two cargo type or when it has subcargoes (r14683) +- Change: [NewGRF] Since our NewGRF handling is better than it used to be, disable a NewGRF if unexpected sprites are reached (r14184) +- Fix: A town could build a statue under a bridge [FS#2618] (r15397) +- Fix: Multiple vehicles could be filling the timetable and only the data from one vehicle would be taken. Now only allow one to be filling at a time [FS#2466] (r15382) +- Fix: When testing for parallel road two tiles away, do not move more than one tile along the road (r15381) +- Fix: [NewGRF] The subcargo returned by vehicle variable 0x42 should be the most-common-subcargo of the most-common-cargo. If nothing is transported 0x..FFFF00 should be returned (r15378) +- Fix: A tram circling around in a depot did never actually 'enter' the depot [FS#2605] (r15375) +- Fix: Changing town road layout in-game caused ugly road networks [FS#2121] (r15340) +- Fix: Company could never have auto-assigned colour 0 (dark blue) (r15281) +- Fix: Deadlock (with wide fonts) or desync when generating manager name (r15279) +- Fix: Close all windows *before* starting a new game/loading a game instead of doing that as one of the latest steps of loading the game. This caused, in some cases, the NewGRF settings to be reset when the game was already loaded resulting in instant desyncs when joining a network game [FS#2577] (r15256) +- Fix: Aircraft could be 'loading in the air' or have zero speed while in air after converting old savegames [FS#2571] (r15230, r15227) +- Fix: Tile error location not reset when levelling land causing a tile to be highlighted when there was nothing to flatten [FS#2542] (r15138) +- Fix: Signs with sign 'Sign' were lost when converting from TTD savegames (r15137) +- Fix: [NewGRF] Add support for 8 byte action7/9 data, used as a mask for GRFID checks (r15114) +- Fix: [NewGRF] Keep industry variables 8E and 8F in sync with 93, when changing production using results 0D, 0E or 0F of callback 29 or 35 (r15103) +- Fix: [NewGRF] Disable a NewGRF from loading if it contains multiple Action 8s (r14979) +- Fix: Wrong defaults for service interval when switching between service interval in days and service interval in percentages [FS#2508] (r14959) +- Fix: [NewGRF] Building new station parts did not allocate a new station spec effectively breaking variable 41. This was due to the limited number of station specs that we can have per station. This fix makes newly build station parts create a new spec until one cannot allocate new station specs anymore and it'll revert to the old behaviour (sharing station specs) [FS#1832] (r14956) +- Fix: [NewGRF] Station specs did not get deallocated when building a new station part over them (r14955) +- Fix: Sharing/cloning/inserting of orders that the/a vehicle (in the shared list) cannot go to (wrong station type etc) [FS#1890] (r14954) +- Fix: The 'animation state' of the bubbles was stored in a variable that was not stored in the savegame. Using a variable that gets saved in the savegame solves the desync and makes it a bit clearer [FS#2512] (r14931) +- Fix: Abort dragging of vehicles in the group window when they are deleted [FS#2500] (r14925) +- Fix: Do not unnecessarily reset the cursor, when a different vehicle is dragged (r14924) +- Fix: [NewGRF] First create all articulated parts of roadvehicles, then call callback 36 capacity, also call it for all articulated parts (r14903) +- Fix: Overflow of number of orders per vehicle [FS#2495] (r14830) +- Fix: Off-by-one causing possible out-of-bounds reads (r14811) +- Fix: In an MP game in SP mode no company would go bankrupt. Furthermore companies that passed the 'bankrupt' period (4 quarters) would not go bankrupt when loading the game back in MP. Now any company that is in MP or not 'currently controlled by the player' in SP will bankrupt [FS#1993] (r14750) +- Fix: Do not let any disaster vehicle (Helicopter or Airplane) target invalid industry (r14746) +- Fix: Memory leak in Action 0x0F (new town names) (r14737) +- Fix: Writing a single char to the config file caused reading outside a buffer (r14729) +- Fix: First transfer the whole load of a vehicle chain to industries before triggering any processing. This reduces callback usage and resolves critical rounding errors when using input-cargo-multipliers instead of production callbacks [FS#2460] (r14705) +- Fix: Zeppeliner (disaster) should target st->airport_tile, not st->xy (r14694) +- Fix: [NewGRF] Gradual filling graphics were not chosen according to the NewGRF spec [FS#2435] (r14678) +- Fix: [NewGRF] Check sprite size when executing action 6 (r14674) +- Fix: [NewGRF] Property 7 and callback 12 were broken for aircraft. Now callback 12 is properly called also for 'mail'. If the callback is not used, 'mail' uses 1/4 of property 7 (rounded up) [FS#2444] (r14672) +- Fix: Possible stack corruption when reading corrupted sprites [FS#2415] (r14610) +- Fix: [NewGRF] Return the current year as construction year for unfinished houses (r14608) +- Fix: [NewGRF] When callback 1E fails, use the standard random colour (r14605) +- Fix: The company ID is off-by-one with respect to the rest of the GUI in the cheat window [FS#2422] (r14603) +- Fix: The range for kicking/banning clients is based on the maximum number of clients, not the maximum number of companies [FS#2414] (r14588) +- Fix: Allow capacity callbacks (15, 36) to return zero capacity (r14578) +- Fix: Crashes when a NewGRF sends an invalid string [FS#2395] (r14563) +- Fix: Order pool seemed to look full when it was not as it only checked whether it was possible to allocate a new block of pool items instead of checking for free pool items (r14547) +- Fix: Do not deliver cargo to industries not inside station catchment area [FS#2138] (r14530) +- Fix: Allocate stub (empty) sound entries when loading an empty/corrupt/incorrectly sized sample.cat instead of making valid NewGRFs fail to load (r14527) +- Fix: Make sure trains stop at the end of a station; a 3/8th length train did stop 2/8th of its length too early causing a 63/8th long train not to fit in a 4 tile station [FS#2379] (r14526) +- Fix: Small possible chance of desync due to sorting on pointer instead of by (station) index [FS#2348] (r14463) +- Fix: When a road stop gets moved make sure to update the destination of RVs going to that road stop [FS#2330] (r14446) +- Fix: Support for spaces in directories passed to ./configure [FS#1802] (r14440) +- Fix: Trains would sometimes move one time too often/little when moving from diagonal<->non-diagonal tracks [FS#1793] (r14436) +- Fix: Balance the monthly random industry changes, by introducing a daily random industry change [FS#1885] (r14332) +- Fix: Save the palette of the loaded NewGRFs in the savegame, so joining with a server using Windows palette will make a client with the DOS palette do palette conversion and (thus) not cause a desync (r14233) +- Fix: Glitches (alignment issues/inconsistent vehicle graphics) in original graphics (r14214, r14211) +- Fix: One could not get a list of vehicles sharing an order when the number of orders was 0; you could see that the vehicles had a shared order though [FS#2085] (r14097) +- Fix: Various assorted autoreplace issues/misbehaviours [FS#1264, FS#2037, FS#2038, FS#2110] (r14083) +- Fix: The autoreplace gui showed vehicle types for replacement which CmdSetAutoReplace() did not accept (r14037) +- Fix: Automatically recalculate inflation if NewGRFs are changed and cargo types are added, so that cargo payment rates are correct [FS#2074] (r13836) + + +0.6.3 (2008-10-01) +------------------------------------------------------------------------ +- Fix: NewGRF VarAction 2 variable 43 for industries saw MP_VOID tiles as land tiles and was inefficient (r14417, r14416, r14415) +- Fix: Possible buffer overrun/wrong parameter type passed to printf (r14414, r14397) +- Fix: Generation seed set using -G was always overwritten by -g (r14408) +- Fix: Do not allow extending signals by dragging in any direction other than the track direction [FS#2202] (r14013) + + +0.6.3-RC1 (2008-09-22) +------------------------------------------------------------------------ +- Fix: Invalid v->u.air.targetairport could cause crashes at several places [FS#2300] (r14383, r14344, r14343) +- Fix: Moving the first vehicle of a train elsewhere might require a new unitnumber for the remaining chain which might not be available (r14384) +- Fix: Trams jumping when reversing on a single trambit (like caused during road construction reworks) or when (manually) reversing in a corner [FS#1852] (r14371) +- Fix: Multiheaded parts in free wagon chains were not connected (could cause desyncs) (r14366, r14362) +- Fix: [Windows] Some keypress combinations could be handled twice [FS#2206] (r14363) +- Fix: The ownership of roadtiles was not properly set for very old savegames (including TTD's) making it impossible to remove some pieces of road [FS#2311] (r14359) +- Fix: Desync due to randomly ordered vehicle hash by flooding and road vehicle overtake/following (r14356, r14258) +- Fix: Signs were not updated on company bankruptcy/sell, and thus could have the colour of invalid player (r14348) +- Fix: Delete the RenameSignWindow when 'its' sign is deleted (r14345) +- Fix: Signs from old savegames were lost (causing little memory leaks) (r14340) +- Fix: When a company was renamed and then manager was renamed before building anything, company name changed (r14328) +- Fix: When you rename a town before building something and build something near that town your company would be called ' Transport' [FS#2251] (r14327) +- Fix: Free any blocks that a helicopter may have on an oilrig when the helicopter gets forcefully removed (bankruptcy). For other airports this is not needed as they cannot be used by multiple companies [FS#2241] (r14324) +- Fix: Possible assert when renaming removed waypoint (r14322) +- Fix: Properly delete orders so the pool does not fill up (r14319) +- Fix: Do not allow building road over level crossings and drive-through road stops in the wrong direction; do not allow adding roadtypes to non drive-through road stops; pay for all added road bits [FS#2268] (r14316, r14315, r14314, r14308) +- Fix: Aircraft frozen above oil rig when the next order is invalid [FS#2244] (r14309) +- Fix: [YAPF] Only reserve road slots for multistop when they are really reachable [FS#2294] (r14305) +- Fix: One could be trying to get the station name of a station that is outside of the pool (r14297) +- Fix: Default for sound effects and music volume should be in the valid range for that setting [FS#2286] (r14289) +- Fix: Make small UFO aware of articulated RVs so they crash the complete vehicle instead of a small part of it (r14270) +- Fix: Desyncs after deleting a waypoint because of explicit destructor call instead of using operator delete (r14265) +- Fix: Merge keycode for 'normal' 0-9 keys and keypad 0-9 keys so people do not get confused that the keypad does not work as expected [FS#2277] (r14260) +- Fix: Clicking on the smallmap did not break the 'follow vehicle in main viewport' [FS#2269] (r14243) +- Fix: The engine-purchase-list-sorter doubled running-cost and halved capacity of double-headed engines [FS#2267] (r14239) +- Fix: Feeder share was computed wrong when splitting cargo packet (r14234) +- Fix: Signs (town name, station name, ...) could be too long for 8bit width in pixels (r14221) +- Fix: 10 days != 6*2.5 days, effectively causing the payment graph to show the wrong data (r14219) +- Fix: When determining length of a string with limited size, first check if we are not out of bounds already (r14204) +- Fix: Properly update the current timetable's travel/wait times instead of only doing it for one vehicle in the shared order chain and only when some bit has not been set [FS#2236] (r14192) +- Fix: Sprite payload skipping would not skip enough bytes in a very small subset of compressed sprites (r14191) +- Fix: After applying NewGRF settings, all rail and road types were available as the engine availability check was performed too early (r14182) +- Fix: Close all related vehicle lists when closing a station window (and not only the train list) (r14180) +- Fix: RemoveOrderFromAllVehicles() did not mark enough windows dirty (r14179) +- Fix: Incorrect cargo weights (r14144) +- Fix: GetSlopeZ() gets a virtual coordinate, not a tile (r14139) +- Fix: Close the 'manage vehicles' dropdown once the number of vehicles in the list reaches 0 [FS#2249] (r14133) +- Fix: [Strgen] Changing order of parameters {X:...} did not work for strings including some {StringY} (r14111) +- Fix: Desync due to bubbles in toyland (r14110) +- Fix: Make NewGRF action 0x06's changes persistent over the several loading stages [FS#1986] (r14102) +- Fix: Make the 'Transfer Credit' display aware of the entire consist, not only the first vehicle (r14098) +- Fix: Do not flood a NewGRF industry when it implicitly tells that it wants to be build on water (land shape flags bit 5) [FS#2230] (r14093) +- Fix: The vehicle window of articulated road vehicles would show the clone/refit button when the vehicle was not completely stopped in the depot (r14090) +- Fix: Flawed parsing of words (as in 2 bytes) in GRF strings due to sign extension [FS#2228] (r14087) +- Fix: Division by 0 in NewAI [FS#2226] (r14062) +- Fix: NewGRF callback 23 did not use the NewGRF compatible text stack [FS#2224] (r14058) +- Fix: NewGRF text stack's 'push word' did not move the data around properly (r14057) +- Fix: Long strings in the edit box would cause OpenTTD to stop drawing the string. This is especially noticeable with low resolutions and the chat input box (r14054) +- Fix: [OSX] Changed the condition for selecting 8 or 32 bpp blitter by default. Now we will pick 32 bpp if no 8 bpp fullscreen resolutions are available on the main display (the one with the dock) (r14032) +- Fix: Crash when the AI tries to find the depot of an airport that does not have a depot [FS#2190] (r13999) +- Fix: MSVC cannot handle changed files in the prebuild event, so make the version determination a separate subproject [FS#2004] (r13998) +- Fix: The dedicated console removed any character that was not a printable ASCII character instead. Now it allows UTF8 formatted strings too [FS#2189] (r13992) +- Fix: Resetting construction stage counter reset more than it should (r13981) +- Fix: Wrong tooltip for the industry directory's list [FS#2178] (r13917) + + +0.6.2 (2008-08-01) +------------------------------------------------------------------------ +- Fix: Custom vehicle names from TTD(Patch) games were lost (r13884) +- Fix: NewGRF Callback 10 (visual effect and powered wagons setting) and powered wagons operation were not performed for articulated wagons [FS#2167] (r13870) +- Fix: In some cases the sprite cache could be filled with unremovable items [FS#2153] (r13869) +- Fix: Return of wrong parent scope of (NewGRF) industry variables (r13868) +- Fix: Loading of TTD(Patch) savegames from the command line did not work (r13859) +- Fix: Buffer overflow for too long filename supplied as '-g' parameter [CVE-2008-3577] (r13858) +- Fix: Cargo type lookup was incorrect for NewGRF version 7 files without a translation table [FS#2157] (r13855) +- Fix: GetTownByTile() is only valid for houses and roads (r13851) +- Fix: Power, running cost and capacity of multiheaded engines were (too often) doubled in newspaper resp. offer window (r13844) +- Fix: FreeType may return a bitmap glyph even if a grey-scale glyph was requested [FS#2152] (r13832) + + +0.6.2-RC2 (2008-07-25) +------------------------------------------------------------------------ +- Fix: Building through the wrong side of a drive through station was allowed [FS#2166] (r13822) +- Fix: Check for vehicle length changes outside a depot (callback 0x11) and give a warning about that [FS#2150] (r13816) +- Fix: Several minor memory leaks. They only happened once per game (r13809, 13810) +- Fix: Checking for train waiting at other side of two-way signal was broken [FS#2162] (r13806) +- Fix: Some revision checking code was unintentionally disabled (r13776) +- Fix: Enforce the validity of a NetworkAction (chat packet) issued by a client (r13775) +- Fix: Selecting non-full length vehicles in the depot gui would place the 'mouse pointer' out of the centre of the vehicle making it hard to 'aim' [FS#2147] (r13759) +- Fix: NewGRF rail continuation would always mark a tunnel on the same axis as connected, even when the tunnel faces the wrong direction (r13734) +- Fix: Assumption that non-north tiles of a house do not have the 1x1 building bit set was flawed with some NewGRFs. This caused the amount of houses to differ, which causes the town radii to differ, which causes desyncs when towns are expanded (r13729) +- Fix: Possible desync on the autorenew settings 20+ game years (i.e. 4.5+ hours) after a company was started (r13718) +- Fix: Any player could construct new companies [FS#2144] (r13716) +- Fix: Remove the unique_id from the message that a client has joined as it is only exposes the unique_id more than needed (r13714) +- Fix: Possible crash on creating a network packet [CVE-2008-3547] (r13713) +- Fix: Enforce the length restrictions of company and president name in the commands too (r13712) + + +0.6.2-RC1 (2008-07-16) +------------------------------------------------------------------------ +- Fix: Possible buffer overflow in string truncation code [CVE-2008-3576] (r13700) +- Fix: Handle SETX(Y) properly when truncating a string instead of ignoring it and returning a too long string (r13699) +- Fix: In some cases the (sound) mixer could overflow causing artifacts in the sound [FS#2120] (r13695) +- Fix: Do not rely on .tar files always ending with a block of zeros (r13693) +- Fix: Make sure a command is ran in the context of autoreplace or not (r13691) +- Fix: In the case that elrails and 'realistic' acceleration are disabled all electrified engines would have no power on load, until the vehicle got turned around, loaded or got into a depot [FS#2102]- Fix: Saving TTD imported games in recession failed due to wrong (and unneeded) type conversions in the saveload code [FS#2131] (r13679) +- Fix: Inactive companies from old (TTD) saves could be marked active in some cases, which then loads garbage in their statistics and such [FS#2126] (r13676) +- Fix: Memory leak when NewGRFs got forcefully disabled and they defined GOTO labels (r13675) +- Fix: Crash when drawing a non-real sprite caused by NewGRF interference [FS#2127] (r13674) +- Fix: Desync when building electrified trains on a dedicated server that was started with electrification disabled [FS#2122] (r13673) +- Fix: Bus/truck forgetting go-to-depot order when entering a non-drivethrough road stop [FS#2117] (r13664) +- Fix: Server crashing when banning the rconning client (r13661) +- Fix: Signals were not updated correctly when a player removed a non-existing track piece (r13626) +- Fix: Crash when one tries to raise the northern corner of MP_VOID tiles (i.e. the southern corner of the tiles on the southern map edge) in the scenario editor [FS#2106] (r13624) +- Fix: Only the front of a RV would be considered when determining to what cargoes a vehicle can be refitted instead of all cargoes [FS#2109] (r13622) +- Fix: If the first bridge can not be build for a given length, then none of the other bridges can. Effectively meaning that if someone replaces the first bridge with a bridge that can be only 3 tiles longs then only other bridges that can be 3 tiles long will be buildable, but only if they are 3 tiles long [FS#2100] (r13611) +- Fix: Signal states could be propagated through waypoints built in orthogonal axis (r13589) +- Fix: [OSX] 10.5 failed to switch to fullscreen (r13584) +- Fix: RVs continuing onto next DT station when they are build adjacent to them [FS#2040] (r13581) +- Fix: Disable static NewGRFs when non-static NewGRFs query them in the context of network games. This makes it impossible for static NewGRFs to disable non-static NewGRFs and 'bad' things happening because the non-static NewGRF does not know about the static NewGRF (r13576) +- Fix: Properly count number of non-north housetiles [FS#2083] (r13518) +- Fix: Incorrect usage of strtoul (r13508) +- Fix: Clear the memory for the new AI during the loading of a savegame so it does not try to execute commands generated in a different savegame, which could be resulting in the AI trying to give orders to stations that do not exist (r13505) +- Fix: Drawing of zoomed out partial sprites could cause deadlocks or crashes (r13502) +- Fix: First determine where to *exactly* build a house before asking a NewGRF whether the location is good instead of possibly moving the house a tile after the NewGRF said the location is good (r13489) +- Fix: Track was not removed on company bankruptcy when there was a ship on lower halftile (r13488) +- Fix: Let ships also navigate on half-tile sloped watery rail tiles (r13485) +- Fix: Division by zero when one would press 'd' (skip order) when there's no order (r13409) +- Fix: Do not crash when resolving vehicle sprite groups with zero sprites (r13397) +- Fix: In the purchase list, CB36 for capacity was not called for the first part of rail and road vehicles (r13385) +- Fix: Loading of very old OpenTTD savegames was broken (r13373) + + +0.6.1 (2008-06-01) +------------------------------------------------------------------------ +- Fix: Industry tiles would sometimes tell they need a 'level' slope when they do not want the slope (r13348) +- Fix: Attempts to make the old AI perform better (r13217, r13221, r13222) + + +0.6.1-RC2 (2008-05-21) +------------------------------------------------------------------------ +- Fix: Do not send rcon commands of the server to the first client but do directly execute those on the server (r13137) +- Fix: For multiheaded engines, halve power and running cost when used instead of when loading, to allow callback values to work properly (r13074) +- Fix: Loading of TTDP savegames with rivers in them [FS#2005] (r13066) +- Fix: Update build industry window when raw_industry_construction setting is modified (r13060) +- Fix: Revert changes to multihead engine weight -- the original values were correct (r13023) +- Fix: Debugging was not possible with MSVC 2008 (r12996) +- Fix: List used for sorting GRFs was not freed (r12993) +- Fix: Default difficulty settings were different to TTD's original settings [FS#1977] (r12951) +- Fix: All vehicles would be available when an original scenario would be played [FS#1982] (r12948) +- Fix: Keep only first 15 bits for non failed callback results (r12947) +- Fix: Reading/modifying invalid data under some circumstances (r12943) +- Fix: Minor errors related to industries accepted/produced cargo (r12933) +- Fix: Town rating was affected even after the test run (r12920) +- Fix: Flood road tiles even when there are road works in progress [FS#1965] (r12919) +- Fix: Do not initialise Station struct with tile=0, buoys will never change that value [FS#1960] (r12915) +- Fix: Game crash when a spectator/server tried to show an engine with no owner when a NewGRF requested a specific variable (r12914) +- Fix: Report reverse sprite status (FD/FE) to NewGRF for manually toggled vehicles (r12910) +- Fix: Vehicles going twice to a depot when the automatic service interfered with the current order [FS#1985] (r12629) + + +0.6.1-RC1 (2008-04-26) +------------------------------------------------------------------------ +- Fix: Vehicle groups, engine replacement rules and player/company names were not properly reset/freed after bankrupt (r12906) +- Fix: Remove trams from savegames saved in OpenTTD without tram support, it is better than to simply crash [FS#1953] (r12904) +- Fix: GCC on FreeBSD does not support -dumpmachine causing configure to fail. Use g++ instead [FS#1928] (r12876) +- Fix: Make the town rating tests use less memory and much quicker (r12859) +- Fix: Usage of AutoPtr made (trying to) build stuff very (time) expensive (r12857, r12855) +- Fix: Ensure that prop 25 is set for all vehicles in the consist before other properties as it could cause desyncs (r12856) +- Fix: Too much catenary was drawn about tunnel entrances, middle bridge pieces and non-rail station tiles (r12853, r12852) +- Fix: Use YAPF for fairly old savegames from before YAPF was introduced (r12845) +- Fix: The industry tick trigger should only be triggered once every 256 ticks, not every tick... Also bail out of the triggers a little earlier if you know they are not going to happen anyway (r12844) +- Fix: Inconsistent use of 8/15-bitness of NewGRF callback results with respect to TTDP's implementation of the specification (r12819, r12818, r12759) +- Fix: Possible out of bounds array access (r12809) +- Fix: Enforce autorenew values range in command (r12808) +- Fix: Vehicles could break down during loading and keep loading. The intention of the break down code is not to break down when having zero speed, therefor break downs now do not happen when loading [FS#1938] (r12795) +- Fix: [OSX] In some rare cases when using an uncalibrated monitor the system colour space could not be retrieved. Show an error when this happens instead of just trying an assertion (r12776) +- Fix: Slope checking for NewGRFs failed (r12759) +- Fix: Check the TILE_NOT_SLOPED flag of the _north_ tile of multi-tile houses to decide if autoslope is allowed (r12717) +- Fix: Do not move windows below the toolbar on resizes unless they would go behind the toolbar [FS#1904] (r12714) +- Fix: Increase default sound buffer size only for Vista [FS#1914] (r12708) +- Fix: Do not crash very hard on unrecognised savegames, just go back to the intro menu instead (r12707) +- Fix: In some cases a news messages would not be shown [FS#1906] (r12683) +- Fix: Removing road pieces from a town gave you twice the intended penalty [FS#1920] (r12682) +- Fix: When a road vehicle has a tram only stop multiple times in a row in its orders, only the first one would be skipped [FS#1918] (r12678) +- Fix: Colour remaps on station sprites only worked for company colours [FS#1902] (r12674) +- Fix: Remove buggy buoys at tile 0 from old TTDP savegames (r12642) +- Fix: Possible NULL pointer dereference when reading some NewGRF data [FS#1913] (r12637) +- Fix: Infinite loop in case your compiler decides that enums are unsigned by default (r12622) +- Fix: The convert signal button disallowed signal dragging when the signal GUI was closed (r12577) +- Fix: Binding to a specific IP could cause OpenTTD to not register properly with the masterserver if one has multiple external interfaces (r12574) +- Fix: The function min() has 32bit arguments, clamping of 64bit values did not work (r12572) +- Fix: Towns could not terraform when inflation raised terraform prices enough (r12564) +- Fix: Do not affect town rating change by the order in which we examine stations (r12561) +- Fix: Redraw the signal GUI when the signal drag density changes in the patch settings and vice versa (r12553) +- Fix: Do not install scenarios into the current user's homedir when running 'make install', that is silly. Simply always install scenarios system wide instead (r12542) + + +0.6.0 (2008-04-01) +------------------------------------------------------------------------ +- Fix: Final formatting of some string codes from NewGRFs was not done correctly [FS#1889] (r12488) +- Fix: Timetable times for aircraft were always doubled [FS#1883] (r12477) +- Fix: Remove broken endian-dependent code and unnecessary rgb to bgr swapping [FS#1880] (r12453) +- Fix: Do not 'disable' the drawing of autorail overlays when the tile is 'error'-marked (red pulsating selection) [FS#1871] (r12439) +- Fix: Plural rule for Icelandic was wrong (r12417) + + +0.6.0-RC1 (2008-03-26) +------------------------------------------------------------------------ +- Feature: Show whether a town is a 'city' in the town description title bar (r12391) +- Feature: Increase house animation frame number from 32 to 128 (r12347) +- Fix: Loading of TTD savegames (r12399, r12401) +- Fix: Vehicle lists related to stations not closed when the station is deleted [FS#1872] (r12393) +- Fix: Trams failing to turn on bridge heads/tunnel entrances [FS#1851] (r123890) +- Fix: Train could break apart when reversed while partially in a depot [FS#1841] (r12386, r12384) +- Fix: Non-breaking spaces should not be broken (r12385) +- Fix: Check return of AfterLoadGame for success or failure when loading TTD games [FS#1860] (r12383) +- Fix: Use 'items' unit for batteries, fizzy drinks, toys and bubbles in total cargo tab [FS#1864] (r12382) +- Fix: The number of houses was not computed right [FS#1835, FS#1535] (r12381) +- Fix: Update train acceleration and max speed after setting cached value to ensure the correct max speed is used with disabled real acceleration (r12380) +- Fix: Refresh vehicle details window when cached values are updated (r12378) +- Fix: Set cached value for vehicle property 25 before other cached values [FS#1854] (r12377) +- Fix: Do not close a dropmenu when clicking on a dropdown widget (r12374) +- Fix: Windows music driver fails if path is too long or if containing non-latin chars [FS#1849] (r12373, r12372) +- Fix: Do not let window hide behind the main toolbar after resizing the screen [FS#1823] (r12371) +- Fix: Close language drop down when parent window is clicked/closed [FS#1853] (r12370) +- Fix: Reset train speed limits when _patches.realistic_acceleration changes (r12369) +- Fix: Commands were sent to clients waiting for map download causing 'executing command from the past' error [FS#1650] (r12367) +- Fix: Do not allow building 'zero' road bits (r12363) +- Fix: Randomise variable 8F only once per callback 28 (r12362) +- Fix: openttdd.grf was using the wrong colours for glyphs due to a grfcodec bug (fixed in grfcodec 0.9.10 r1837) (r12360) +- Fix: Some callback-results were treated as 8 bit, when they were 15 bit, and vice versa (r12352, r12358) +- Fix: Do not try to flood water tile [FS#1836] (r12350) +- Fix: NTP skipped junction just after bridge end (r12348) +- Fix: Remove duplicated and inconsistent code wrt. autoreplace with rules in both vehicles' group and ALL_GROUP [FS#1748, FS#1825] (r12346) +- Fix: Do not try to restore backupped timetable when timetabling is disabled [FS#1828] (r12345) +- Fix: Slow helicopters never got the 'chance' to finish the landing routine (r12343) +- Fix: GRM buffer for cargoes was incorrect size [FS#1827] (r12341) +- Fix: Recalculate cached train data after clearing reversing flag when entering depot (r12339) + + +0.6.0-beta5 (2008-03-04) +------------------------------------------------------------------------ +- Feature: Vehicle variable FE bit 5, 6 and 8 [FS#1812] (r12331, r12330) +- Feature: Support loading full range of 0xD0xx NewGRF strings which includes 0xD000 to 0xD3FF (r12316) +- Feature: Ability to change aircraft speed factor, from so called 'realistic' (matching other vehicles) (1/1) to original TTD speed (1/4) (r12293, r12294) +- Change: Update readme about where openttd looks for files (r12321) +- Fix: Do not pause/unpause the game when showing load/save windows when the game is paused due to missing GRFs [FS#1733] (r12336) +- Fix: Disallow building level crossings over one-way roads as this allowed competitors to remove the one-way state [FS#1819] (r12329) +- Fix: Wrong Y pillar specified for girder with arch bridge (r12328) +- Fix: Vehicles could be sorted in a wrong order when a vehicle name changed - cached name was not invalidated (r12324) +- Fix: Vehicle sorting by name was broken, it was comparing the same string (when caching was not used) [FS#1821] (r12323) +- Fix: Endian issue when saving/loading group owner (r12322) +- Fix: Wrong transparency options could be saved after toggling all [FS#1817] (r12320) +- Fix: Map string IDs that are embedded from other strings [FS#1815] (r12317) +- Fix: Include prop 25 data for all train parts, not just those that carry cargo (r12314) +- Fix: YAPF and NTP did not apply penalty for uphill tracks on steep slopes (r12313) +- Fix: Restore timetable from backupped orders and add group ID to the backup [FS#1549] (r12296) +- Fix: Do not draw trees nor lamps between tram tracks (r12290) [FS#1807] +- Fix: [Windows] Do not create save dir on install (r12269) +- Fix: Autoreplace did not update vehicle index for timetable window [FS#1805] (r12261) +- Fix: GetProductionAroundTiles() may fail if only the second production slot exists (r12258) +- Fix: Town variables 0x9E to 0xAD (company ratings) returned wrong values (r12247) +- Fix: Typo resulting in no players are given the engine preview offer (r12244) +- Fix: Mac OSX bundle display name should be 'OpenTTD' [FS#1798] (r12234) +- Fix: [NewGRF] Support using any base price for rail and road vehicles' running cost, show running cost of wagons if available (r12209) +- Fix: When loading a savegame fails, do not start creating a new game, just go straight back to the intro screen (r12202) +- Fix: Force AI to build rail or road instead of bridges if possible, so it does not build bridges everywhere (r12200) +- Fix: 'Transparent buildings' now only toggles buildings, so show tick when buildings are transparent [FS#1789] (r12198) +- Fix: Show correct last year profit when the train had negative income [FS#1788] (r12197) +- Fix: There can be oil rigs at map borders, do not set water class for them [FS#1787] (r12195) +- Fix: Do not start overtaking if the RV reaches wrong-way one-way-road in the next tiles (r12191) +- Fix: Assert when trying to play tile sound at NW border of map (placing buoys, levelling land) [FS#1784] (r12186) +- Fix: Take into account possible loan when AI is deciding which bridge to build, so it will not build wooden bridges every time (r12184) + + +0.6.0-beta4 (2008-02-18) +------------------------------------------------------------------------ +- Feature: Allow buttons to resize in NewGRF settings window (r12172) +- Feature: Change colour of autorail and autoroad selection when Ctrl is pressed (r12167) +- Feature: Separate catenary transparency settings from building transparency settings (r12103) +- Feature: Allow locking individual transparency settings so they will not be changed by pressing 'x' (r12102) +- Feature: Add some missing VarAction2 variables (r12124) +- Feature: Make snow appear on rail tiles dependant on track height, not on height of the lowest part of the tile (r12098) +- Feature: [NewGRF] Specify the purchase, rail and road description of a bridge (r12069) +- Feature: [NewGRF] Add support for var 12, Variational Action 2 (r12045) +- Feature: Allow trees on shore (r12029) +- Feature: Invisible trees are now separate from the building concept (r12022) +- Feature: Add support for passenger engine designation for AI-use, NewGRF property 0x08 for trains (r12019) +- Feature: Show all cargo sources (en-route from) in the station view cargo waiting list instead of just one (r11990) +- Feature: [NewGRF] Resizable industry view window on callback 3A (r11987) +- Feature: [NewGRF] Implement var 8F (random bits) during callback 28 [FS#1697] (r11985) +- Feature: [NewGRF] Add support for Action 0D, var 13: information about current map size (r11961) +- Feature: Support Action5 type 0D (newwater) (r11947) +- Feature: Allow building bridge heads on more slopes (r11937) +- Feature: [NewGRF] Add support for Rivers. Rivers can currently only be placed with-in the scenario editor (r11926, r11938, r11949, r12071) +- Feature: Generate.vbs script to allow project files generation for users unable to run generate bash script (r12123) +- Feature: Sort the strings in languages dropdown (r11886) +- Codechange: Drop MSVC 2003 support (r11979) +- Fix: Test purchase list loading/loaded sprites instead of unconditionally returning a possibly non-existent sprite (r12180) +- Fix: Return correct bridge price for AI when DC_QUERY_COST is set [FS#609] (r12171) +- Fix: When drag&drop mode was cancelled by keyboard input, depot/group window was not updated [FS#337] (r12166) +- Fix: Buffer overflow when drawing scrolling news [FS#1652, FS#1773] (r12165) +- Fix: If a train is 'stopping' when entering a depot, do not let it leave again [FS#1705] (r12163) +- Fix: Towns should not build over houses owned by another town [FS#1757] (r12162) +- Fix: Towns will no longer build houses > 1x1 there where should be road (with 2x2, 3x3 grid town layouts) (r12161) +- Fix: Remove the arbitrary limit of 64 waypoints per town [FS#1744] (r12160) +- Fix: Chance16I was now biased towards zero - round to nearest now (r12156) +- Fix: Adjust aircraft slowing algorithm (r12144) +- Fix: Callback 0x3D always gets a cargobit in var 0x18, independent of grf version [FS#1766] (r12142) +- Fix: Do not allow adding tram to rail-road crossing when there is a vehicle on it (r12138) +- Fix: Show cargo capacity for articulated vehicles correctly in the purchase list. Multiple cargo types can also now been shown [FS#1769] (r12137) +- Fix: With mammoth trains disabled, maximum train length was limited to 9 (r12131) +- Fix: Use tile index 0 for planes in the air, so it cannot have an invalid tile index [FS#1745] (r12109) +- Fix: X/Y axis swap for station tiles in GetNearbyTile() was wrong way around [FS#1753]( r12108) +- Fix: Loading older savegames fixes (r12096, r12097) +- Fix: When a company bankrupts, remove drive-through road stops, ship depots and buoys too. Update owners of water and road [FS#1703] (r12095) +- Fix: Do not set station owner for buoys when merging company (r12093) +- Fix: Keep production level within delimited boundaries, while using var result 0D/0E and than multiplying/dividing it [FS#1755] (r12092) +- Fix: Assert when loading savegame with wrong tiletype at south map borders (r12088) +- Fix: Check overrides only for industries when mapping NewGRF entities to 'real' entities [FS#1747] (r12086) +- Fix: Update waypoint signs when changing language (r12080) +- Fix: Use search paths when opening console scripts (r12079) +- Fix: When reusing a renamed deleted waypoint, keep the new name (r12076) +- Fix: Make docks at sea flood neighboured tiles (r12072) +- Fix: Possible deadlock when there are no houses available to build at given tile (r12062) +- Fix: Houses with zero probability could be built (r12062) +- Fix: Do not clear tiles when the town will not be able to build any buildings anyway (r12060) +- Fix: Allow building 2x2 building on slopes if not explicitly forbidden (r12060) +- Fix: It was possible to build 2x1 and 1x2 buildings on slopes even if it was not allowed (r12060) +- Fix: Teach NPF where road vehicles and trams can reverse (r12058) +- Fix: Ships can drive through opponents' ship depots (r12058) +- Fix: Slowdown train when approaching 90deg turn when 90deg turns are forbidden (r12057) +- Fix: Enable YAPF to start searching inside a wormhole [FS#1704] (r12056) +- Fix: Another way to fix AI trying to build road through depots (r12055) +- Fix: The cargo translation table was loaded at the right time, but all the other global variables were now loaded too early [FS#1737] (r12052) +- Fix: Random_func broke for desync debug (r12050) +- Fix: Memset on multibyte array with wrong byte count (r12049) +- Fix: Crash when centring on a vehicle (aircraft) that is outside of the map [FS#1741] (r12044) +- Fix: Allow building transmitters and lighthouses on tree tiles [FS#1736] (r12043) +- Fix: Reimplement how rivers and canals are stored in the map, allowing the sea/river/canal status to also be stored for buoys, docks, locks and depots. All these are now allowed on rivers and removal of them will revert to the original water type [FS#1676] (r12042) +- Fix: Change ownership of or remove statues when merging/bankrupting companies (r12038) +- Fix: For station tiles, only get road types for road stops (r12036) +- Fix: Teach YAPF where trams can reverse, and where not [FS#1702] (r12035) +- Fix: Do not show train speed as zero after loading paused game (r12033) +- Fix: When removing a statue, remove town statue flag for the statue owner, not current player (r12032) +- Fix: Prevent towns from removing or claiming ownership of player owned tiles when growing [FS#1689,FS#1719] (r12031) +- Fix: In one case trees could spread under bridges (r12024) +- Fix: Put a better suited text in the quit-dialogue [FS#1690] (r12023) +- Fix: Restore initial intent on the invisible tree while transparent building patch setting [FS#1721] (r12018) +- Fix: When you have more than 9 network interfaces you'll enter the wonderful world of overflows (r12017) +- Fix: Better work on strings in regard to gender [FS#1716] (r12015) +- Fix: Lighthouses and transmitters were never supposed to be build on a slope (r12014) +- Fix: When modifying watered tiles, mark neighboured canals and rivers dirty in more cases (r12013) +- Fix: Enable TownRatingTestMode during cost estimation with 'shift'-key (r12012) +- Fix: Do not consider one-corner-raised-shores to be watered tiles from all sides [FS#1701] (r12011) +- Fix: Avoid loading sample.cat if it 'looks' incorrect, and avoid later null pointer dereferences by moving volume lookup deeper [FS#1707] (r12009) +- Fix: Possible reading from an invalid pointer [FS#1717] (r12005) +- Fix: When skipping Action 11 or 12, also skip belonging sprites (r12001) +- Fix: Do entrance-slope-check for every tile of railstations (r11999) +- Fix: Possible remote assert by setting bit 6 of p1 for CMD_REMOVE_ROAD [FS#1692] (r11998) +- Fix: Update train statusbar when stopping from zero speed [FS#1706] (r11996) +- Fix: Resize station/road stop/dock/airport construction windows if cargo acceptance list is too long (r11993) +- Fix: When building two rail stations close to each other (with control) so they looked like one long track trains would see them as one (r11992) +- Fix: Resize autoreplace window to fit purchase information text if it is too large (r11989) +- Fix: Build system ignored changes to table/control_codes.h which require strgen to be rebuilt (r11986) +- Fix: Also draw corner shores under rail tracks (r11984) +- Fix: Use unicode glyph mapping to fix up missing/shuffled sprites in original data files instead of shuffling or skipping sprites directly [FS#1698] (r11981) +- Fix: Industries using results 0D/0E on callback cb29/35 were a bit too eager to close down (r11976) +- Fix: Shore and sea tiles under bridges were converted to canals in old savegames [FS#1684] (r11974) +- Fix: Use grass tiles for corner shores, if shores got replaced by ActionA [FS#1683] (r11973) +- Fix: Old AI should not build fast planes with a small airport in orders(r11972) +- Fix: MP_ROAD can have railbits too - OPF searching over rail of diffen t owner behind crossing (r11967) +- Fix: OPF was searching through depots and normal road stops [FS#1403, FS#1506] (r11966) +- Fix: Tropic zone data was returned incorrectly [FS#1685] (r11964) +- Fix: NewAI could not build any road vehicles when there were any tram grfs loaded (r11958) +- Fix: Disallow building locks and docks on rapids [FS#1675] (r11956) +- Fix: Do not allow modifying roadbits when other roadtypes would need different foundation (r11953) +- Fix: Loading of very old savegames was broken (r11951) +- Fix: Slope detection of bridge ramps. Helps YAPF and Trolly (r11946) +- Fix: [Windows] FileExists() failed for non latin paths (r11945) +- Fix: Allow building drive-through road/tram stops at road/tram track that has no owner (r11944) +- Fix: 'BRIDGE_TOO_LOW_FOR_TERRAIN'-check was wrong for steep slopes (r11936) +- Fix: [Autoreplace] Single to dualhead locomotive replace failed when player had enough money to replace and refit one but not enough to refit the last one as well [FS#1624] (r11929) +- Fix: [Autoreplace] Autoreplace could refit train engines to the wrong cargo type if the old engine had no cargo capacity and the new one had (r11928) +- Fix: Loading old, pre savegame version 2, savegames (r11925) +- Fix: AI was reading wrong tile slope while building road bridge (r11917) +- Fix: Set correctly crossing state after train reversal, train leaving crossing, train crash (r11900) +- Fix: Segmentation faults/wrong frees due uninitialised memory in the AI [FS#1658] (r11887) +- Fix: Assert when trying to remove rail from a house or industry tile [FS#1663,FS#1665-6-7-8,FS#1680,FS#1686-7-8 FS#1715 FS#1742 FS#1771 FS#1776](r11883) +- Fix: Crash in MP in vehicle group window if the currently selected group is deleted by another player (r11878) +- Fix: Another way to crash competitors' train in a station (r11877) +- Fix: Automatically sending aircraft to depot for autoreplace/renew is now triggered by the correct conditions (r11875) +- Fix: EngineHasReplacementForPlayer() did not look in ALL_GROUP (r11872) +- Fix: Do not update signals after each tile when building/removing a large block of track/signals/station [FS#1074] (r11871) +- Fix: Slow down train when approaching tile we cannot enter in more cases (r11870) +- Fix: Do not make crossing red when we cannot enter it in any case (r11870) + + +0.6.0-beta3 (2008-01-16) +------------------------------------------------------------------------ +- Feature: Replaced fixed size custom name array. Names are now attached to their object directly and there is no limit to the amount of names (r11822) +- Feature: Add drag-n-drop support to the raise/lower land tools. Land is raised/lowered at the start and the rest of the area levelled to match (r11759) +- Feature: Add support for NewGRF's train 'tilt' flag. Trains with tilt capability (specific details are per NewGRF set) will be given a 20% speed limit bonus on curves (r11741) +- Feature: Added sorting for cost, running costs and speed to road vehicles and ships build windows (r11710) +- Feature: List neutral stations where the player has service in the station list too (r11670) +- Feature: Check whether (some) characters are missing in the current 'font' for the 'currently' chosen language and give a warning when that does happen (r11646) +- Feature: Support shore replacement via Action 5 (r11726) +- Fix: When two NewGRFs 'fight' to define the same cargo it could happen that the strings are defined by one cargo and the 'action2' by another and when one assumes that both come from the same NewGRF [FS#1559] (r11862) +- Fix: Recompute town population when removing a 'newhouses' grf, or when loading a game with missing 'newhouses' grfs [FS#1335] (r11855) +- Fix: Road vehicle count was incorrect in network lobby window (r11844) +- Fix: Mark dirty canal tile even in diagonal direction from flooded tile, draw correctly canal next to half flooded rail tile (r11843, r11838) +- Fix: At least one instance of dmusic driver is needed for it to be registered and usable (r11826) +- Fix: An articulated road vehicle could split up when it turned around at a corner and then would enter a drive through station at the next tile [FS#1627] (r11825) +- Fix: Switch _screen to the output buffer and disable usage of 32bpp-anim animation buffer during giant screenshots [FS#1602] (r11813) +- Fix: Do not crash trains when leaving depot to a very long track [FS#716] (r11802) +- Fix: Take town rating into account when testing if a command can be executed [FS#1616] (r11795) +- Fix: Reversing a train when loading at a station with an adjacent station in the same axis crashed [FS#1632] (r11794) +- Fix: Group names got not deallocated in the command test run [FS#1614] (r11743) +- Fix: Run window tick events when paused, so that news pop-ups and the about window still progress. For other windows the events are ignored when paused [FS#1319] (r11742) +- Fix: Modify and possibly discard key events for code points in the unicode private use area [FS#1610] (r11740) +- Fix: Set the new scroll position after zooming in instead of before, as the zoom will cancel it out [FS#1609] (r11739) +- Fix: Do not reset loading indicator IDs when only reloading NewGRFs [FS#1574] (r11735) +- Fix: Elrail merge gave elrail, monorail & maglev unintended speed bonuses for curves, as the bonus was based on the railtype index. The bonus is now specified by a property of the railtype (r11732) +- Fix: Clear sprite override data before performing NewGRF wagon attach callback. This stopped the callback working for autoreplace and when moving wagons from train to train in a depot [FS#1582] ( r11731) +- Fix: If there are no houses that can be build in a specific year yet, force the houses with the earliest introduction year to be available [FS#1577] (r11727) +- Fix: Make it impossible (for users) to circumvent the length checking of the NewGRF 'allow wagon attach' callback by moving several wagons at a time (r11724) +- Fix: Do not put more than one Random() in function calls because parameter evaluation order is not guaranteed in the C++ standard [FS#1561] (r11716) +- Fix: Do not allow player inauguration date on scenarios to be bigger than current year [FS#1569] (r11714) +- Fix: Add more house string id ranges to MapGRFStringID so NewGRFs use the proper string ids (r11712) +- Fix: Do not allow refitting flooded (destroyed) vehicles (r11707) +- Fix: Trains could have sprites with wrong direction when reversing, also was inconsistent with save/load process [FS#1557] (r11705) +- Fix: When removing buoys, return to water or canal depending on their owner (r11666) +- Fix: Animation information should not be copied from original industry tile spec, while doing an action 00, industry tile, prop 08 (r11665) +- Fix: Do not allow modifying non-uniform stations when non-uniform stations are disabled [FS#1563] (r11659) +- Fix: 'Initialised' NewGRFs could still be deactivated in the later 'activation' pass (r11650) +- Fix: Vehicles were still followed when sold [FS#1541] (r11632) +- Fix: Many viewports could crash the scenario editor [FS#1527] (r11629) +- Fix: Popping from text reference stack must be done in a precise order. But some compiler (MSVC) over optimised it and inverted this order [FS#1532] (r11627) +- Fix: There were still some cases where one could not build a tram track, but the tram could become blocked [FS#1525] (r11621) +- Fix: Do not make crossing red behind depot the train is entering [FS#1531] (r11619) +- Fix: Buoys are just waypoints, so do not allow load/unload/transfer for them (r11618) +- Fix: Sometimes large values could go off the chart [FS#1526] (r11616) +- Fix: Temperate banks can only be built in towns (over a house) (r11615) + + +0.6.0-beta2 (2007-12-09) +------------------------------------------------------------------------ +- Feature: Allow setting a default password for new companies in network games (r11556) +- Feature: Signal selection GUI for the ones that really like to use that over CTRL (r11547) +- Feature: Make the bridge selection window resizable (r11539) +- Feature: [OSX] Added support for using Quartz instead of Quickdraw in windowed mode on OS X 10.4 and higher (r11496) +- Feature: Allow to resize on creation the smallmap gui in order to show all the types industry available, allow to enable/disable individually or all at once, the industries shown on small map (r11474) +- Codechange: Send and store the passwords a little more secure to/in the servers (r11557) +- Fix: Wrong error messages were shown when trying to build some industries in the scenario editor [FS#1524] (r11609) +- Fix: [NewGRF] Do not trigger industries, but only the industry's tiles (r11608) +- Fix: Wrong count of Kirby trains when a ship was build [FS#1482] (r11605) +- Fix: Tiles were not marked dirty in some cases when removing a lock or flooding (r11582, r11604) +- Fix: Make price for railtype conversion more realistic; conversion should not be more expensive than removing and rebuilding [FS#1481] (r11603) +- Fix: Do not allow changing network only patches settings from console when not in network game (r11594) +- Fix: IsSlopeRefused() result was half wrong causing banks to be built on wrong places (r11590) +- Fix: When ship depots got destroyed they always returned to water, even when it should have been canals [FS#1514] (r11589) +- Fix: The one way road button was not reset on abort (r11587) +- Fix: Windows could get completely missing when one resized the window to something very small [FS#1484] (r11583) +- Fix: Invalidate 'list trains/roadvehs/ships/planes' widgets when station part is added/removed so it does not become glitchy (r11577) +- Fix: Flood train stations when there are no trains on border tiles too (r11574, r11570) +- Fix: Reinitialise windows system before loading a savegame because not doing so can cause crashes [FS#1494] (r11572) +- Fix: Road vehicle getting to the wrong side of a station when trying to overtake in there [FS#1493] (r11571) +- Fix: Full paths sometimes did not work correctly [FS#1480] (r11568) +- Fix: Break the chain before moving a vehicle after another in the same chain instead of causing an infinite loop [FS#1512] (r11566) +- Fix: Aircraft sometimes stopped mid-air when the airport got destroyed [FS#1503] (r11562) +- Fix: Group list was not updated when removing the last group [FS#1504] (r11561) +- Fix: Overflow when drawing graphics with high company values [FS#1505] (r11558) +- Fix: If ever the air/heliport is suddenly not available while the 'chopper' is descending, just go back into flying instead of stopping mid air [FS#1496] (r11546) +- Fix: Cargo translation was sometimes done when it should not be done [FS#1501] (r11544) +- Fix: [OSX] Detect statvfs at runtime (based on OSX version) instead of compile time. This should prevent a crash on OSX 10.3 with the precompiled binaries (in the load/save windows) (r11541) +- Fix: [OSX] Do not try to compile the quartz video driver on OSX 10.3 as it will fail (r11540) +- Fix: Do not do all kinds of 'updates' for town, waypoint, station and other signs when you have not converted the map to the 'current' format as that means you are going to read data in the 'old' format when you assume that it is in the 'current' format, which is eventually going to break (r11525) +- Fix: Assertion when tram reversed at a station [FS#1485] (r11524) +- Fix: The scrollbar of the network gui could run out of bounds (r11522) +- Fix: [OSX] The cocoa video driver let the mouse cursor escape the window when using rmb scrolling (r11520) +- Fix: Signs totally illegible when transparent signs is turned on and zoomed out more than one level [FS#1463] (r11507) +- Fix: Selling vehicles could cause the window of others to scroll to that location [FS#1471] (r11506) +- Fix: Do not do standard production change if callbacks 29/35 failed, disable smooth economy for industries using callbacks 29/35 (r11502) +- Fix: Two small layout issues with the vehicle grouping GUI (r11478) +- Fix: A road vehicle must not show that it is driving max speed when it is standing still waiting for the vehicle in from of it [FS#1451] (r11477) +- Fix: OpenBSD has ALIGN already defined, causing compilation failures [FS#1450] (r11467) +- Fix: Operator priority problem resulting in problematic autoroad placement in some cases (r11466) + + +0.6.0-beta1 (2007-11-18) +------------------------------------------------------------------------ +- Feature: Make news messages related to the industry (production) changes better configurable; you can now disable news messages popping up for industries you are not servicing (r11442) +- Feature: When sorting stations by cargo sum, only sum the cargoes that are selected in the filter (r11437) +- Feature: Show all players who have shares, not just the first two (r11435) +- Feature: Make OpenTTD's sprites replaceable using Action 5 and make replacing contiguous subsets of sprites in for some types possible in Action 5 (r11433) +- Feature: Allow town-bridges to be build on slopes (r11395) +- Feature: Auto-road; same as auto-rail, but for road and trams and only on X and Y direction (r11339) +- Feature: OpenTTD version checking for NewGRFs. This allows NewGRFs to do something different for different versions of OpenTTD, like disabling it for too low versions or loading different graphics (r11330) +- Feature: Half tile- and anti-zig-zag-foundations (r11319) +- Feature: Control-Clicking the Centre Main View button on the vehicle window allows the main viewport to follow the chosen vehicle (r11304) +- Feature: User customisable faces (r11269) +- Feature: Make more advanced rail types more expensive to build (r11265) +- Feature: Implement the 'moreanimation' feature of TTDP, so we can properly support newindustries (r11228) +- Feature: [NewGRF] Add support for newindustries (r11204) +- Feature: Sort the NewGRFs by name, making searching a specific NewGRF a lot easier (r11175) +- Feature: Add possibility to show the bounding boxes of sprites using CTRL-B so one can get a better understanding of the used bounding boxes to fix the glitches that still exist. Note that showing the bounding boxes is not glitch free; it only gives you some knowledge where the bounding boxes are (r11174) +- Feature: Remove the arbitrary limit of 10 articulated parts for a vehicle (r11120) +- Feature: Autoslope, changing of slopes of tiles that already have something build on them. Does not work for tiles of houses/industries/stations that do not allow autosloping (r11107) +- Feature: Support for encapsulating files into a .tar file; you can pack all files in your data/ directory in how ever many .tar files you like, keeping the directory-structure equal to the unpacked version, and OpenTTD can handle them just like the files were unpacked (r11106) +- Feature: Allow slopes under statues (r11069) +- Feature: [OSX] Added more options for right click emulation (controlled from the interface tab in the patch window) (r10996) +- Feature: Allow building and removing tracks and signals when there is a train on a parallel diagonal track that does not interact with this one (r10922) +- Feature: Added TileHeight to the Land Area Information tool [FS#653] (r10878) +- Feature: [OSX] OpenTTD will now pick the same language as finder is set to if no config file is found (r10851) +- Feature: Provide an infrastructure to have resizable windows that are smaller than the default window size. Useful for playing on very low resolution systems (r10704) +- Feature: Support for autosave_on_exit in the console, so dedicated servers can use it (r10658) +- Feature: Add a soft limit of 4096 'entities' in a station's waiting queue and a hard limit of 32768 so (malicious) people cannot cause a 'denial of service' attack by filling cargo lists (r10555) +- Feature: Replace all the windows for Industry building by a more flexible one (r10496) +- Feature: Support for 'prospecting' raw industries, i.e. you pay an amount of money and then it might (with a given chance) build a raw industry somewhere on the map (r10451) +- Feature: Automatic signal completion, enabled by pressing CTRL when dragging signals. Signals will continue following track until an existing signal, junction or station are reached. This currently replaces the existing use of CTRL-drag for changing existing signal type (r10437) +- Feature: New sign editor features including switching to previous/next sign (r10401) +- Feature: Disallow (in the GUI) the building of infrastructure you do not have available vehicles for. This means that the airport building button is disabled till you can actually build aircraft. The game itself will not disallow you to build the infrastructure and this 'new' behaviour can be overridden with a patch setting [FS#669] (r10353) +- Feature: Add the possibility of automatically filling in timetables based on the times from the first (or subsequent) run-throughs (r10331) +- Feature: Option to select the 'default' rail type when you start a new game or load a game. This is done either static, i.e. rail, electrified rail, monorail and maglev, or dynamic which takes either the first or last available railtype or the railtype that is used most on the map [FS#812] (r10329) +- Feature: Give a better explanation why the loading of a savegame failed and do not crash on loading savegames that were altered by patches or branches [FS#917] (r10300) +- Feature: A sticky button for the client list window [FS#885] (r10293) +- Feature: Allow double-clicking on certain places: add NewGRF window, build-vehicle and town-action (r10265, r10267) +- Feature: Loading indicator, which shows in % how full a vehicle is while loading/unloading (r10254) +- Feature: Introduce a form of timetabling for vehicles (r10236) +- Feature: [NewGRF] Add support for action 0F (town name generator) (r10211) +- Feature: Add support for personal directories on Windows (r10182) +- Feature: Add support for anti aliased typefaces via FreeType. This is configurable for each font size in the configuration settings and requires using the 32bpp blitter and suitable fonts (r10166) +- Feature: 32 bpp sprite support and dedicated driver does not blit nor render by default. Can be overruled by user (r10121) +- Feature: Add support for articulated road vehicles (r10097) +- Feature: Allow moving of orders instead of removing them and readding them somewhere else [FS#828] (r10071) +- Feature: Replace hard coded spritecache size with a configuration option, sprite_cache_size. The default size is 2MB and the value can range from 1 to 64MB. If you experience slow-downs when scrolling the map, try increasing this setting (r10042) +- Feature: Skip to the selected order in the order list when clicking on the 'skip' button while pressing CTRL [FS#760] (r10033) +- Feature: Sort the strings in server language dropdown and the town names dropdown (r10032, r10036) +- Feature: Build windows of trains, road vehicles and ships can now be sorted by cargo capacity (planes already had this option) (r10024) +- Feature: More languages flags for servers [FS#790] (r10017) +- Feature: Allow different signal types on one tile [FS#362] (r10006) +- Feature: Support for oneway roads (r9999) +- Feature: Add smooth viewport scrolling. This must be enabled with patch setting 'smooth_scroll' (r9962) +- Feature: Allow terraforming under bridges (r9950) +- Feature: Support for trams (r9923) +- Feature: Allow building new stations adjacent to existing stations by holding down control (r9905) +- Feature: Add one new zoom-out level: 8 times (r9884) +- Feature: Advanced vehicle lists a.k.a. group interface. Now you can make groups of vehicles and perform all kinds of tasks on that given group (r9874) +- Feature: Make 'improved loading' a proper improved loading instead of loading one (semi-)random vehicle at a time. Furthermore fill multiple vehicles at once when there is enough cargo to do so (r9838) +- Feature: Add drag and drop removal of station tiles (r9810) +- Feature: Support for 'curvature info', Action 2 for train, variable 45 (r9803) +- Feature: [NewGRF] Add action 1, 2 and 3 support for canals (r9797) +- Feature: Add the possibility to choose different road patterns for towns to use (r9779) +- Feature: Add an option to automatically pause when starting a new game (r9734) +- Feature: Add the concept of cities. A (configurable) proportion of towns can start off larger, and will grow twice as quickly as other towns (r9667) +- Feature: Add NewGRF Action 5 (Sprite Replacement) support for 2cc colour maps, airport, and road stop sprites (r9645) +- Feature: Increase cargo types from 12 to 32 and enable newcargo flag in NewGRF loader (r9638) +- Feature: Make it possible to have some control over the town growth (r9613) +- Feature: Add list_patches console command. This shows all patches along with their current values (r9565) +- Feature: Add more finer control to transparency options, including a new toolbar (r9563) +- Feature: Add support for variable snow lines in the arctic climate, supplied by NewGRF files (r9371) +- Feature: [NewGRF] Add support for newhouses (r9315) +- Feature: [NewGRF] Add support for Action 13, which allows you to translate GRF-specific texts. The translations will only be shown if you are using a language with a GRF language id and if a string has not already been set specifically for the language you are using (r9037) +- Feature: Translation dependant formatting of dates (r8906) +- Feature: If an action 7/9 leads to skipping the rest of the file, disable the NewGRF if an action 8 has not been encountered yet (r8831) +- Feature: Stop loading and disable the current NewGRF if a fatal error message in Action B is encountered. Also be more strict on the values accepted (r8830) +- Feature: Build aircraft windows will no longer show aircraft that cannot use the airport in question (r8771) +- Feature: Drive-through road stops (r8735) +- Feature: Allow upgrading bridges by building a new bridge over the top (r8567) +- Feature: Provide aircraft with vertical separation depending on their altitude and velocity (r8534) +- Feature: When linking the terraform toolbar to the build toolbars place them side by side instead of on top of each other (r8436) +- Feature: The vehicle build windows are now resizable in horizontal direction as well (r8331, r8336, r8338) +- Feature: Automatically build semaphores before a configurable date, which can be set by each network player separately (r8151) +- Feature: Increase sprite limit from 16384 sprites to 16777216 sprites (r8128, r8129) +- Feature: Add the ability to load savegames when you do not have the exact GRF files in your list. GRF files that are found based on GRF ID (but not on matching md5sum) are used instead of disabling them. This does not affect MP games, there you still need an exact match (r8106) +- Feature: Show the activated status of the GRF list after pressing 'apply' in the NewGRF window, instead of the local list (r8094) +- Feature: The station list does now remember the sort settings (r8065) +- Feature: Make it possible to override the bind address and port of a dedicated server from the command line (r7802) +- Feature: Add command line option to prevent saving of high score and configuration on exit and a console command to manually initiate a configuration save (r7801) +- Feature: Add support for tractive effort to 'realistic' acceleration (r7592) +- Feature: Allow to build bridges of arbitrary rail/road combinations (including signals) (r7573) +- Codechange: Do not allow configuration changes, that NewGRFs can directly use to change their behaviour, during network games as this can cause desyncs (r11452) +- Codechange: Make opening a new toolbar not overlapping its parent one, by locating it under the parent, and aligned with the left side of it [FS#1310] (r11256) +- Codechange: Do not brute force determine the first vehicle in the chain or previous vehicle, but do it by properly accounting the previous and first pointers when updating the next pointer. This gives a performance increase of about 15% when there are a lot of vehicles in the game (r11011) +- Codechange: Cache expensive NewGRF station variables during sprite lookups/callbacks (r10509) +- Codechange: Keep track of the origin, time of travel and accumulated feeder share (transfers) of individual pieces of cargo. This means that cargo is not thrown on a big pile when it is put in a station or unloaded at a station, however the GUI does not reflect these changes yet so you will not actually see it (r10266) +- Codechange: Do not limit the cost of tunnels (r10248) +- Codechange: Add new vehicle hash table for collision detection and finding vehicles on a tile. The hash area scanned is far smaller than the old hash table, which is now used for viewport updates only. This should give a significant performance improvement for games with many vehicles (r10111) +- Codechange: Do not redraw all station tiles when cargo is added or removed if the station has no custom graphics (r10062) +- Codechange: Add some support for NewGRF var 7D, temporary storage array (r9707) +- Codechange: Add support for returning 'TTDPatch variables' (Action D) (r9701) +- Codechange: Implement NewGRF callback 36, which allows changing of various properties which were previously static (r9671 and several others) +- Codechange: Add support for multiple 'base' directories for NewGRF searching (r9560) +- Codechange: Implement actions 1/2/3 for cargoes, callback handler and custom icon sprites (rmany) +- Codechange: Rename the 'New ' button of the global vehicle lists to 'Available ' as it is a view-only list, not one from which you can purchase (rolling) stock (r8420) +- Codechange: Remove the landscaping button from the build toolbars (r8143) +- Codechange: [NewGRF] Do not mark as unsafe those NewGRFs that set their own parameters (via action D) and/or change only bridge sprite table layouts (action 0, property D) (r7831) +- Fix: The CHANCE16 functions were biased; a 32768 in 65536 chance was really a 32769 in 65536 chance (r11454) +- Fix: Do not create shores in canyons (r11438) +- Fix: Starting OpenTTD with DOS files made it look weird out of the box (r11433) +- Fix: Properly support genders coming from NewGRFs instead of crashing [FS#1430] (r11422) +- Fix: Do not ignore the autorenew settings for new games when creating a new game [FS#1428] (r11415) +- Fix: Do not do a 270 degree turn when 90 degrees is enough on a commuter airport [FS#1422] (r11408) +- Fix: In rare cases OpenTTD could segfault when resizing and scroll the main window (r11405) +- Fix: Manually replacing a vehicle with shared orders makes it lose it is order index and service interval [FS1384] (r11370) +- Fix: Road vehicles must not drive through each other on bridges/in tunnels [FS#1258] (r11366) +- Fix: When stopping a ship or aircraft, set their speed to 0 so they will not continue at the speed where they were stopped at [FS#1288] (r11365) +- Fix: Cloning vehicles with non-standard sub-cargotypes (i.e. livery refits) failed [FS#1380] (r11362) +- Fix: Loading too many GRFs was not handled gracefully causing crashes and such [FS#1377] (r11355) +- Fix: Add missing elrail sprites for some rail build buttons/cursors (r11350) +- Fix: Trees can now be planted on bare land without making it grassy, planting tree in desert does not make it grassy for the first tile-cycle and when a tree dies in desert, it no longer becomes a snowy tile for the first tile-cycle (r11244) +- Fix: The explosion vehicles were placed too far to the south [FS#1312] (r11234) +- Fix: One could sell vehicles that were crashed in a depot, which would still yield money/one could construct trains of crashed vehicles [FS#1307, FS#1228] (r11229, r11230) +- Fix: Electric trains were not shown as stopped in depots when converting it from elrail -> normal rail [FS#1260] (r11167) +- Fix: A lot of graphical glitches by changing some bounding boxes. It is not perfect yet, but a *very* good step into the right direction (r11128) +- Fix: When autorenew is enabled and it cannot renew the vehicle anymore (because the player cannot build the engine), the ageing warnings as if autorenew is not enabled are shown [FS#553] (r11064) +- Fix: Inconsistency between rail<->elrail conversions of different kinds of rail containing tiles (normal rail, stations, depots, etc) [FS#1182] (r11059) +- Fix: Crash when having the Finance window opened of the player you are cheating to [FS#1177] (r11028) +- Fix: Switching players (using the cheat) crashed on Big Endian machines [FS#1150] (r11023) +- Fix: The canal border determination did not take oil rigs into consideration (r11022) +- Fix: Do not display income/expenses when they do not belong to a 'valid' tile, like the money cheat/giving money [FS#1175] (r11021) +- Fix: One could not give money when (s)he had too much money or rather: when casting the amount of money to an int32 becomes negative [FS#1174] (r11020) +- Fix: When determining the gender of a string, do not assume that the gender is in the front of the string when there can be case switching code at that location [FS#1104] (r10792) +- Fix: Determining whether there is a tunnel going under the lowered area is only needed in two directions instead of all four, so take the directions (one for each axis) to the nearest border (along the given axis) [FS#1058] (r10686) +- Fix: Graphical glitches when the 'link landscape toolbar' patch is turned on when opening one of the construction toolbars [FS#1076] (r10685) +- Fix: Trolly AI did not know about steep slopes, and used wrong tileh in some cases [FS#1070] (r10655) +- Fix: Be consistent with the space between the company name and the player number, i.e. always put a space between them [FS#1052] (r10627) +- Fix: [YAPF] Ships received curve penalty for non-diagonal straight move (r10578) +- Fix: Do not segfault when you quit in the end-of-the-game screen [FS#1020] (r10548) +- Fix: When Cheat-Window is open and a new month happens, the window was not redrawn instantly (r10547) +- Fix: You can now have both Available Train as Available Ship window open [FS#1026] (r10546) +- Fix: Cargo payment rates overflow and cargo payment rates diverge from cost rates making it impossible to make any profit after a certain number of years. Both are solved by stopping the inflation after 170 years; there is absolutely no point in continuing the inflation after that as it only makes the game have overflows at some point that cannot be solved; using larger variables only delays the inevitable [FS#1028] (r10541) +- Fix: Error dialogue was sometimes shown on all clients when a command failed instead of only the client that actually did the command [FS#1015] (r10501) +- Fix: The network protocol check for required NewGRFs sent static NewGRFs too (r10414) +- Fix: When landscape generating, allow for 200ms between screen updates instead of updating every 200ms. Previously slow screen updates would result in very slow map generation (r10396) +- Fix: One could only build a limited number of stations before one had to rename them [FS#278] (r10320) +- Fix: Acceleration not calculated properly when a train goes up a hill between tunnels [FS#786] (r10317) +- Fix: [YAPF] Now it is no longer needed to invalidate the YAPF segment cache every tick in MP (read performance increase). Segment cost now does not contain the curves between segments. As a result the cache should be now accurate (r10302) +- Fix: [YAPF] Assertion triggered in some special cases [FS#901] (r10301) +- Fix: Flush stdout on dedicated server output to ensure an update of stdout [FS#775] (r10295) +- Fix: With smooth_economy, when industry production hit 32, it stayed there for ever. Give it some chance to get out of that uber-lowness (although it is a very slim chance, at least it has one) (r10290) +- Fix: Also age engines that are not front-engines [FS#202] (r10288) +- Fix: Money overflow bugs in many locations [FS#723] (r10212) +- Fix: Fix issues related to fixed names, fixed places of files/directories and application bundles [FS#153, FS#193, FS#502, FS#816, FS#854] (r10182) +- Fix: A vehicle without visual effects is not per definition unpowered (r9802) +- Fix: Do not assume that trains running on monorail/maglev cannot smoke/spark (r9801) +- Fix: Play sound effects based on the engine class, not the rail type (r9800) +- Fix: Separate engine class and engine running cost class (r9799) +- Fix: Clone vehicles will no longer refit for free (r9689) +- Fix: Improved loading does not use a huge amount of processing power anymore when having a lot of trains [FS#423] (r9683) +- Fix: Truncate the NewGRF information text in the NewGRF GUI if it is too long (r9449) +- Fix: Cancel in password queries reduces amount of players in the network game when they have not joined the game yet [FS#688] (r9378) +- Fix: If all news-setting buttons show 'full', make the ALL-button show 'full' too (r9137) +- Fix: Open and close messages now have their own setting, so you can hide economy changes, but do show open/close of industries [FS#525] (r9097) +- Fix: Do not make owner signs transparent, as then you loose the information who it owns [FS#637] (r9067) +- Fix: Store the owner of a statue, so when it gets removed, the town is notified of it [FS#638] (r9066) +- Fix: Inactive connections are not automatically kicked, i.e. people who only open a telnet (or similar) connection to a server [FS#115] (r9038) +- Fix: Do not select a disabled platform length/number of track count when going out of drag-drop mode [FS#450] (r8999) +- Fix: Make an aircraft at 400 km/h go as fast as a train at 400 km/h (r8973) +- Fix: You were unable to build roads in the scenario editor when there is no town 0, even though there are other towns (r8608) +- Fix: Road Vehicles now can obtain a slot even if the station is very spread out [FS#577] (r8536) +- Fix: Allow lumber mill to cut trees only when they are full grown (r8535) +- Fix: Segmentation fault when the toolbar gets removed and you have selected one of the items in a sub menu of the toolbar (r8533) +- Fix: Remove phantom oil rigs sometimes present in old savegames (r8485) +- Fix: When a station is removed, vehicles do not get excessive payment any longer, as the origin TILE is now stored as long as the origin STATION for the transported cargos (r8144) +- Fix: The game could crash when the chat key () is pressed too vehemently during the join of the game. Your client's id does not exist in the clients list yet, and returns NULL (r8132) +- Fix: Rail vehicles can no longer enter tunnels or bridgeheads with wrong railtype (r7976) +- Fix: When path finding onto a bridge or tunnel end from previous tile (but not warping from the opposite end) check the enter direction. This fixes signal setting if a rail ends on the top of a tunnel end (r7718) +- Fix: When following path for signals, do not skip back to the previous tile, as for tunnels and bridge ends the entering direction is wrong (r7717) +- Fix: [YAPF] Suppress 'Train is lost' message if path finding ended on the first two-way red signal due to YAPF.rail_firstred_twoway_eol option (r7628) +- Fix: [OPF] Signal update was incorrectly propagated (r7620) + + +0.5.3 (2007-09-15) +------------------------------------------------------------------------ +- Fix: Possible NULL pointer dereference that could be triggered remotely (r11074) +- Fix: Removing CMD_AUTO from some commands could remotely trigger an assertion [FS#1179] (r11040) +- Fix: Underflow that caused overflows in the performance rating [FS#1179] (r11039) +- Fix: [Windows] MIDI does not stop when closing openttd [FS#1164] (r11029) +- Fix: Do not unconditionally assume that a tile has a depot (r11027) +- Fix: Give a more correct error when building some things on tile 0 [FS#1173] (r11024) +- Fix: Do not display income/expenses when they do not belong to a 'valid' tile, like the money cheat and giving money [FS#1175] (r11021) +- Fix: One could not give money when (s)he had too much money [FS#1174] (r11020) +- Fix: Disallow buying/selling shares in your own company or a bankrupt company [FS#1169] (r11018) +- Fix: Crash when quiting the game in one of the end score windows [FS#1218] (r11071) + + +0.5.3-RC3 (2007-08-30) +------------------------------------------------------------------------ +- Fix: Spectators are not allowed to issue commands (r11006) +- Fix: Make the AI not crash when it has ships as the AI does not support them [FS#1133] (r10942) +- Fix: Trains would not get flooded when they are at the lower part of a tile that would become a coast tile after flooding [FS#1127] (r10892) +- Fix: Removing road with the road removal tool would also work with a negative bank account, making the bank account even more negative than it was [FS#1125] (r10890) +- Fix: Some isocodes were wrong, resulting in some NewGRF not working properly for the affected languages (r10877) +- Fix: [Windows] Do not try to minimise or restore the window when closing OpenTTD [FS#998] (r10835) +- Fix: Trains going over bridges would get the 'going down hill' accelerate bonus, which causes trains to go faster on bridges than they would be going on level land [FS#1096] (r10739) +- Fix: Trains being split into two pieces when loading an old savegame [FS#1062] (r10735) +- Fix: [OS/2] Fix chdir problem with open/save dialogue (r10650) +- Fix: One could not remove locks that were build in a (very) old version of OpenTTD [FS#1038] (r10593) +- Fix: One cannot navigate using arrow keys in the game name text box [FS#1038] (r10500) +- Fix: Ship's maximum speed wrongly shown [FS#1013] (r10497) +- Fix: [OSX] Of the resolution is changed to something that is too high for the monitor, then it is reduced to fit the monitor size, solving several crashes and graphical glitches [FS#458] (r10410) +- Fix: NPF was leaking memory each time it got initialised, except for the first time (r10357) +- Fix: [YAPF] 'target_seen' flag that is set prematurely in some cases (1 tile long cached segment followed by target station) which caused asserts to trigger [FS#884] (r10199) + + +0.5.3-RC2 (2007-07-07) +------------------------------------------------------------------------ +- Fix: Visual glitches when a window is resized in the WE_CREATE callback (r10465) +- Fix: [Windows] _wnd.has_focus was not properly set after using ALT-TAB [FS#962] (r10399) + + +0.5.3-RC1 (2007-06-28) +------------------------------------------------------------------------ +- Feature: Make the client list window (for network games) stickyable (r10293) +- Feature: Console command to get the current game date (r10137) +- Fix: Waypoints could be renamed when you are not the owner (r10368) +- Fix: Smooth economy did not close primary industries and it allowed increasing of production of industries that should not have rising productions (r10348, r10347, r10290) +- Fix: Acceleration for trains on slopes is not calculated properly [FS#786] (r10344, r10317) +- Fix: The 'old' pathfinders (OPF and NPF) for road vehicles could not find a path when in a tunnel [FS#290] (r10345) +- Fix: Only add the autoreplace menu when autoreplace actually knows about the group [FS#880] (r10337) +- Fix: Signal state sometimes not properly set when the signal 'pathfinder' reached the end of a line [FS#910] (r10336) +- Fix: News messages were shown over the endgame/highscore windows [FS#943] (r10333) +- Fix: Rail could be destroyed when building tunnels (r10306) +- Fix: Flush the output of the dedicated server console (r10295) +- Fix: The 'pause' key did not work in the scenario editor (r10294) +- Fix: Age non-front engines too (so when you move engines around in the depot they do not get age 0 when they are much older [FS#202] (r10288) +- Fix: Do not make everyone spectator if 1 joining client failed to create new company (r10284) +- Fix: Remove invalid characters (for the file system) from savegame names [FS#916, FS#850] (r10272, r10116) +- Fix: Some old savegames could have the wrong bits unset (r10268, r10147) +- Fix: Do not look in every direction for tunnels when building one, one direction is enough (r10258) +- Fix: [Windows] Do not mess desktop when using ALT-TAB [FS#876] (r10251, r10186) +- Fix: Take the age of the front vehicle for station rating (r10246) +- Fix: Terraforming wipes out canals. Now you always have to remove the canal before terraforming, instead of 'just' removing the canal [FS#594] (r10240) +- Fix: Only 2 trains could crash at one time as collision checking stopped on the first hit. This could technically cause desyncs in network games as the collision hash order is not guaranteed [FS#892] (r10222) +- Fix: Land under foundations was terraform when it should not be terraformed [FS#882, FS#890] (r10219) +- Fix: Do not make a 270 degree turn on the international airport when a 90 degree turn is enough (r10187) +- Fix: Crash when trying to get the aircraft movement state of an aircraft going to a just deleted airport [FS#874] (r10165) +- Fix: Airports did not flood when there are aircraft on the airport [FS#601] (r10155) +- Fix: Some vehicles were not drawn when having a high resolution and a high zoom-out level [FS#870] (r10154) +- Fix: Vehicles disappear when crossing certain tiles [FS#869] (r10153) +- Fix: Train disconnects in some old TTD savegames [FS#862] (10151) +- Fix: OpenTTD assumes that the resolution is at least 1 by 1, so force the resolution to be always at least 1 by 1 (r10139) +- Fix: When you got a sufficiently small resolution, there is a possibility for a division by zero when a sound is played (r10138) +- Fix: When removing a dock, a ship will always try to reach the old location of the dock even when it cannot anymore because it the old location of the dock is now land instead of water [FS#810] (r10131) +- Fix: SetCurrentGrfLangID returned the wrong language ids for most languages (r10130) +- Fix: Some NewGRFs use the same (unused in the 'current' climate) sprite IDs. Normally this gives some artifacts, but when one NewGRF expects it to be a sprite and another NewGRF overwrites it with a non-sprite nasty things happen (drawing a non-sprite crashes OpenTTD) [FS#838] (r10109) +- Fix: Multiple subsequent 'give money' actions could result in duplicate messages that money has been transferred when it only happened once, or tell you paid money when you did not [FS#834, FS#839] (r10087, r10085) +- Fix: 'Deactivate Electrified Railways' did not work [FS#836] (10083) +- Fix: Memory leaks in the networking code [FS#846, FS#844] (r10082, r10075) +- Fix: Coverage area highlight was still show when it was turned off for docks [FS#835] (r10068) +- Fix: Do not use override engine type for articulated wagon parts (r10048) +- Fix: Sprite resulting from '?' substitution was reloaded into the cache entry for SPR_IMG_QUERY instead of the original sprite cache entry. This resulted in unaccounted missing sprite cache memory, and was exacerbated because the original missing sprite was not cached, so it did it again and again and again. Slowdowns and boom (r10038) +- Fix: One could build on (some) slopes when building on slopes was disabled [FS#823] (r10030) +- Fix: When deleting the first engine of a train with multiple engines, only reopen the train window if the player had the original train window open. This fixes 'random' windows opening for multiple players of the same company (r10028) +- Fix: When selling trains, if there were no wagons between multiheaded engines the rear part could be checked despite having already been deleted (10023) + + +0.5.2 (2007-05-29) +------------------------------------------------------------------------ +- Feature: Add threading support for MorphOS (r9759) +- Fix: Bridges and tunnels were not always removed on bankruptcy, thus leaving tunnels/bridges with an invalid owner that would crash the game when clicking with the query tool on them (r9966) +- Fix: Null pointer dereference under MorphOS and AmigaOS (r9861) + + +0.5.2-RC1 (2007-05-16) +------------------------------------------------------------------------ +- Feature: Windows 95/98/ME check in Windows 2000/XP/2003/Vista builds (r9834) +- Feature: Add password protected status to 'players' (network server) console command (r9771) +- Feature: Add server_lang in [network] section of openttd.cfg (r9716) +- Fix: Loading some TTDP savegames caused an instant assertion on loading (r9857) +- Fix: [NewGRF] Catch occurrence of division-by-zero in varaction handling (r9837) +- Fix: Only non dedicated servers cannot have 0 players [FS#765] (r9785) +- Fix: Remove arbitrary limit on length of NewGRF strings (r9775) +- Fix: [NewGRF] Ignore axis-bit of station tile layouts [FS#756] (r9758) +- Fix: [Windows] Dead key and open/close console (r9728) +- Fix: When you have closed the 'Load game'/'New game' windows which you started from the 'start server' menu, you should not start a server when starting a new game [SF#1244842] (r9757) +- Fix: Trains were lost after autorenewal/autoreplace [FS#732] (r9753) +- Fix: Stop flooded towns from building roads on water [FS#598] (r9743) +- Fix: Station signs were not resized when the language changed [FS#672] (r9741) +- Fix: In news history, newlines were not replaced with spaces [FS#677] (r9731) +- Fix: Crash when destroying bridge with train partially on it [FS#738] (r9726) +- Fix: Planes made a 270 degree turn instead of a 90 degree turn on the southern runway of the intercontinental airport [FS#743] (r9725) +- Fix: In-game private messages did not work for clients with high ClientIDs (r9719) +- Fix: Do not allow building of rail vehicles whose railtype is not available (r9718) +- Fix: [YAPF] The guessed path was ignored for ships [FS#736] (r9694) + + +0.5.1 (2007-04-20) +------------------------------------------------------------------------ +(None) + + +0.5.1-RC3 (2007-04-17) +------------------------------------------------------------------------ +- Feature: Add list_patches to console commands; shows all patches and values (r9565) +- Fix: Select 'Custom' in the difficulty settings gui when changing a setting [FS#733] (r9647) +- Fix: Building rail on steep slopes ignored build_on_slopes patch setting (r9602) +- Fix: Wrong characters in Finnish town names (r9641) +- Fix: When checking for no vehicle on ground-tiles, do not take into account vehicles that are in the air (r9542) +- Fix: Bankrupt AIs no longer buy over themselves (also added safeguards to prevent in future) (r9540, r9541) +- Fix: When company is removed, sell all shares of the and in the company (r9533) +- Fix: Crash when 2 or more clients joined at roughly the same time (r9529) +- Fix: Custom currency was overwritten and fix euro introduction (r9467, r9469) +- Fix: Values of diff_custom and snow_line in .cfg were not checked properly (r9455) +- Fix: When deleting a vehicle which has shared orders with one more vehicle and no orders, segfaulted (r9429) + + +0.5.1-RC2 (2007-03-23) +------------------------------------------------------------------------ +- Fix: Crashes when the chatbox would be drawn outside of the main window [FS#701] (r9420) +- Fix: Reading out of an array caused a segmentation fault [FS#694] (r9394) + + +0.5.1-RC1 (2007-03-20) +------------------------------------------------------------------------ +- Feature: Translation dependant formatting of dates (r8906) +- Feature: Kick inactive initial network connections after some time [FS#115] (r9038, r9061) +- Feature: Add an extra news group for opening and closing of industries (r9097) +- Codechange: Disable shares by default and increase the default maximum distance from edge for oil refineries (r9339) +- Codechange: When you started openttd with '-g' you got the same map every run (r9205) +- Codechange: When all news-setting buttons are 'full', make the for-all button show 'full' too (r9137) +- Codechange: Disable the ability to make flooding water with the canal build tool. In the scenario editor you can still make both canals and flood water at height level 0 [FS#622, FS#629] (r9105, r9115) +- Codechange: The station list, sorted by cargo rating, now takes stations into account that have no cargo waiting [FS#595] (r9062) +- Fix: Close the Shared Order Vehicle List if you remove the shared link with only 2 vehicles (r9338) +- Fix: A34-1000, Z-Shuttle, and Kelling K1 are now listed as small aircraft (r9298) +- Fix: Shared orders got messed up when the 'first' trains got removed in the depot [FS#685] (r9277) +- Fix: Use a less CPU-intensive algorithm to find a random industry for the AI to prevent it slowing down the game [FS#644] (r9251) +- Fix: When loading games, enroute_from was updated in the wrong place, causing issues with TTD savegames/scenarios (r9147) +- Fix: 'Train is lost' message is generated incorrectly [FS#676] (r9146) +- Fix: Difficulty level button was not selected when opening the difficulty window (r9117) +- Fix: The wrong catenary wires were drawn for tunnel entrances [FS#612] (r9077) +- Fix: The intercontinental airport used 'T-junction' runway sprites when there is no exit in the middle of the runway as in the city airport [FS#529] (r9076) +- Fix: [Windows] Dedicated console now does not need an extra 'enter' to fully quit [FS#459] (r9074) +- Fix: Take over companies properly in multiplayer games [FS#459] (r9071) +- Fix: When a bribe failed and you have not picked up cargo yet, you would never be able to do so for a given station [FS#404] (r9070) +- Fix: Do not keep on scrolling for non-numeric values in settings, but require reclick [FS#663] (r9064) +- Fix: The personal (.openttd) directories were hidden in the load/save directory listings [FS#652] (r9043) +- Fix: Desync caused by buffer overflow [FS#664] (r9027) +- Fix: When cutting strings into multiple lines also take into consideration whitespace characters of more than 1 byte length (r9012) +- Fix: Play the correct engine sound based on the engine type instead of the sprite (r9009) +- Fix: New locomotive names were not announced in the news, it said 'new railway locomotive available - railway locomotive' [FS#581] (r9000, r9001) +- Fix: [NewGRF] Do not select a disabled platform length/number of track count when going out of drag-drop mode [FS#450] (r8999) +- Fix: [Windows] Resolution doubled in cfg file when fullscreen mode used [FS#642] (r8994) +- Fix: The industry list should also be (re)set when the number of industries is 0 [FS#656] (r8980) +- Fix: [Windows] Possible buffer overflow if unicode text is pasted into an input box and needs trimming (r8975) +- Fix: [Windows] Support compilation with the Vista Platform SDK (r8974) +- Fix: Crash on loading savegames with GRFs that do not have their GRF info/name set (r8955) +- Fix: [NewGRF] Support for vehicle variable 48 was wrong (r8943) + + +0.5.0 (2007-02-27) +------------------------------------------------------------------------ +- Feature: Add the ability to load newer TTDP games (the tile information for coasts has changed) (r8738) +- Feature: Selecting 'end of orders' and deleting will delete all the vehicle's orders (shared mode unchanged) (r8685) +- Codechange: Call GetFirstVehicleInChain only for trains thus increasing performance in large games (r8744) +- Fix: Possible crashes, problems with aircraft and airport removal (r8921) +- Fix: Do not show the 'edit sign' window for spectators (r8808) +- Fix: Adhere order types for ship order insertion to determine destination type (r8802) +- Fix: It was possible to take over buoys by building a station next to them (r8794) +- Fix: Cloning unaware of articulated locomotives that could refit without refitting the front unit (r8777) +- Fix: Loading times for overhanging trains are miscomputed (r8709) + + +0.5.0-RC5 (2007-02-08) +------------------------------------------------------------------------ +- Feature: Requery gameservers that did not respond to their first query (r8520, r8542) +- Feature: Logging of the IP address and port of invalid/illegal UDP packets (r8490) +- Codechange: Replace missing sprites with a red question mark (r8634) +- Codechange: Add Korean, Simplified Chinese and Traditional Chinese languages as an official translation (r8286, r8324, r8616) +- Codechange: Increase the size of the sound/video/music-drivers to 32 bytes (instead of 16) so their actual parameters can be passed. Sound has for example bufsize' and 'hz' (r8497) +- Codechange: Be more strict about language generation and fail any languages not having the mandatory ##name, ##ownname and ##isocode pragma's (r8253) +- Fix: Draw canal edges under buoys that are in a canal (r8635) +- Fix: Buoys on canal tiles do not flood anymore (r8620) +- Fix: Store the ownership of a water tile in the buoy tile and set the ownership of the water tile when the buoy is removed. Prevents certain abuses (r8619) +- Fix: When the currently selected player in the performance details window is no longer active, choose the first active player instead of the first player as that may also be inactive [FS#582] (r8612) +- Fix: Road vehicle very close after another (slower) road vehicle gets its speed reset to 0 when entering a tunnel, which causes a traffic jam outside of the tunnel (r8609) +- Fix: Bridges do not get destroyed when the bridge head gets flooded and there is a vehicle on the bridge [FS#564] (r8593) +- Fix: Road Vehicles now can obtain a slot even if the station is very spread out [FS#577] (r8536) +- Fix: Segmentation fault when the toolbar gets removed and you have selected one of the items in a submenu of the toolbar (r8533) +- Fix: Deleting a vehicle with shared orders, but no orders would fail to reset prev_shared and next_shared (r8294) + + +0.5.0-RC4 (2007-01-18) +------------------------------------------------------------------------ +- Feature: Increase spritecache size to 2MB, will increase performance in games using NewGRF files (r8218) +- Feature: OS/2 support with GCC (Watcom is dropped) (r8042) +- Codechange: Add Japanese, Slovenian language as an official translation and split Norwegian into Bokmal and Nynorsk (r7987, r8084, r8069) +- Codechange: Show error messages about our own data files as a popup, or to stderr if console is available (and not to stdout) (r8013, r8134) +- Codechange: Change the ordering of the network list, compatible servers just missing grf files are below fully compatible servers, not on the bottom (r8118) +- Fix: Return proper error value when unthreaded save fails, prevents server sending 0-sized files (r8171) +- Fix: Network client crashes when a server sends a 0-sized savegame [FS#556] (r8167) +- Fix: Several desync fixes (incorrect road stop update of old games, autoreplace bugs) [FS#551] (r8137, r8147, r8157) +- Fix: Some disaster-events fixed: combat chopper shoots from right position, submarine once again moves around (r8140, r8158) +- Fix: 'out of sprite memory' warning messages due to incorrect assumption of requested memory for sprites (r8133) +- Fix: Buoys are now built and numbered 1..9 not 9..1 [FS#538] (r8123) +- Fix: Clicking for more news properly cycles through the news history backwards, and does not show the first item doubly if it is already open (r8049) +- Fix: Crash when removing a town in the scenario editor while the query window is open for one of the town's tiles (r8030) +- Fix: Overflow of system-ticks was not handled properly, resulting in a possibly unresponsive server/client (r8028) +- Fix: Automatic pause interfering with 'pause_on_join setting' in MP when is pressed [FS#486] (r8027) +- Fix: Picking up en-route cargo will also have virtual profit deducted for trains as well (r8026) +- Fix: Out-of-bounds read access on _clients array (harmless) (r7984) + +0.5.0-RC3 (2007-01-07) +------------------------------------------------------------------------ +- Codechange: Add Lithuanian language as an official translation (r7806) +- Fix: The configure script did not work work for dash, a sh compatible shell [FS#485] (r7893) +- Fix: [OSX] Control + enter no longer fullscreens, interfered with team-chat (r7886) +- Fix: Offset engines/wagons by half width in details window; fixes overflowing for display (r7864) +- Fix: [OSX] Remove incorrect debug message about missing grf files (r7766) +- Fix: [SDL] Sometimes ALT-TAB could trigger the fast forward (r7727) + + +0.5.0-RC2 (2006-12-31) +------------------------------------------------------------------------ +- General Removed support for OSX older than 10.3.9. Either upgrade, or use 0.4.8 (compatible with OSX 10.2) +- Codechange: Drastically reduce the CPU usage in certain cases (AI using CheckStationSpreadOut()) (r7585) +- Fix: Internal bug in updating the animated_tiles table caused desyncs between (different endian) machines in MP (r7631) +- Fix: Signal update got propagated through incompatible railtypes and under certain circumstances tunnels and rail on top (r7620) +- Fix: Remove landscaping toolbar option from road construction toolbar in scenario editor [FS#473] (r7586) +- Fix: The server could under certain circumstances tell a client too late to start syncing if it has been waiting to join (r7566) +- Fix: Removing towns in scenario editor did not remove their subsidies causing possible crashes [FS#468] (r7563) +- Fix: Internal and (patches) GUI were disagreeing about autorenew settings [FS#431] (r7561) +- Fix: No new company could be created if more than 8 clients were connected, even if not all 8 companies were used (r7560) +- Fix; Clicking 'full load' could under certain circumstances change the current depot order [FS#456] (r7559) +- Fix: Do not wait till a crashed vehicle is removed before starting to load other vehicles [FS#464] (r7558) +- Fix: MorhpOS compile and install fixes (r7548) +- Fix: Removing rail station cost was calculated on occupied area not on number of tiles with an actual station on (r7547) + + +0.5.0-RC1 (2006-12-21) +------------------------------------------------------------------------ +- General fixes and improvements to TTDPatch's NewGRF format, most noticeable are newstations, newsounds, more callbacks and I18n +- Added languages: Bulgarian, Esperanto, Russian, Ukrainian, Languages with proper diacretics: Czech, Hungarian, Turkish +- Feature: Show NewGRF compatibility of network games; green for full compatibility, yellow for missing NewGRFs and red for invalid revision (r7505) +- Feature: Load a list of NewGRFs from the config (in the [NewGRF-static] section) that should always be loaded (r7490) +- Feature: Double the length of the cargo and rating indicators in the station list window for better visibility (r7466) +- Feature: NewGRF set up window and browser which allows modification and viewing of NewGRF settings ingame or the main menu (r7357) +- Feature: Support for saving NewGRF settings with savegames (r7348) +- Feature: Add support for gradual (un)loading of vehicles (r7326) +- Feature: Add freight trains patch option which is a multiplier for the weight of cargo on freight trains, to simulate longer heavier trains (r7269) +- Feature: UNICODE/UTF8 support, with (optional) usage of fonts rendered by Freetype instead of sprites. This means full unicode support (input, rendering, file/io) and greatly enhanced internationalisation for non-latin languages (utf8) (r7182) +- Feature: Add Slovak, Brazil and Slovenian currency [SF 1243657, 1171147; FS#131] (r7160, r5964) +- Feature: Allow towns to be built on top of trees in the scenario editor [FS#396] (r7152) +- Feature: Allow over-building of compatible railtypes, i.e. normal and electrified rail. If building electrified rail, normal rail is upgraded for you (at a cost) (r7106) +- Feature: Additional positioning for long dropdown lists with scrollbar support if dropdown list would not fit (r7086) +- Feature: [Windows] Remember the window size between restarts when quit in fullscreen mode (r7061) +- Feature: Increase the chatbuffer of chat messages, messages longer than the graphical box will be wrapped to a new line (r6956) +- Feature: Allow typing longer text than visible for an editbox; it will scroll properly now (r6954) +- Feature: Allow spectators to team-speak to each other (r6933) +- Feature: Allow for ' to be in console tokens. Escape them with \. eg \' (r6875) +- Feature: Change the functionality of the chat window. SHIFT+ENTER (SHIFT+T) sends a message to all players, CTRL+ENTER (CTRL+T) sends a message to all team mates and ENTER (T) is customisable (r6824) +- Feature: (Train is) lost message is now generated immediately when pathfinder cannot find the path (r6800) +- Feature: Add a measurement tool that will show dimensions and height differences of various draggable tools (r6758) +- Feature: Added sort options to the build aircraft and train windows (r6708) +- Feature: Depot lists are now sorted, so vehicle 1 is always first and so on (r6652) +- Feature: Ability to pause a server if not enough players are connected. The setting for this is 'min_players' (r6628) +- Feature: Ability for servers to execute a script just after a client has connected, e.g. for a MOTD, etc (r6625) +- Feature: Add refit commands to vehicle orders (can only be done in goto depot orders) (r6624) +- Feature: Support cargo subtypes in the refit window. The refit window has been altered to support resizing and scrolling (r6601) +- Feature: Depot and vehicle list windows reworked a bit with more buttons to include 'Autoreplace all' (instantly), 'Sell all', 'Start all' and 'Stop all' (r6542, r6552, r6515) +- Feature: Using goto depot with a different control selection will now alter the service/stopping in depot flag instead of cancelling the goto depot order (r6295) +- Feature: When automatically detecting the language try to first match language+territory (e.g. de_CH), then just language (e.g. de) and fall back to en_GB otherwise (r6290) +- Feature: Add a 'goto depot' button to various vehicle list windows (r6229, r6246) +- Feature: Save max_companies/clients/spectators in the config file (r6170) +- Feature: Vehicle status bar will show the heading string in different colours to visually discern the difference between a service and a forced stop (r6165, r6414) +- Feature: Control clicking Goto Depot will now make the vehicle service instead of stop in depot (r6165) +- Feature: List of vehicles with the same shared orders, accessible from the orders-window of a given vehicle (r6161) +- Feature: Added -s (source) and -d (destination) to strgen to specify paths for input and output files (r6089) +- Feature: After removing a farm, its farmland is removed too (over time) [FS#82] +- Feature: Clicking twice on the location button in the smallmap centres to your position, clicking twice centres your viewport [FS#54] (r6040) +- Feature: Change the original date format to a 32 bits format based at the year 0. Highest date is the year 5.000.000AC (r5999) +- Feature: Auto-completion in chat-window. It completes Player and Town names (in that order) using (r5968) +- Feature: Catalan Town Names generator [FS#261] (r5965) +- Feature: Possibility to generate scenarios by importing heightmaps. It can be in PNG or BMP format +- Feature: New (optional) landscape generator based on TerraGenesis Perlin noise with GUI, progress bar and fine-tuning options (r5946) +- Feature: Filter for textboxes to only allow input of certain patterns (like numbers only) (r5944) +- Feature: [Windows] Remember the maximised state of the game window and restore on start [FS#234] (r5874) +- Feature: Add an icon to the SDL openttd executable (r5872) +- Feature: Also allow horizontal and vertical rails on steep slopes (r5864) +- Feature: Allow building of (certain) rails, roads and bridge ramps on steep sloped tiles (r5833) +- Feature: Replacing from a train engine without cargo capacity to one with cargo capacity will now make autoreplace refit the engine to carry the cargo type from the last wagon in the train (r5465) +- Feature: [OSX] Macs with touchpads that support two finger scrolling can now use this 'scrollwheel' to scroll up/down (r5460) +- Feature: Allow building canals at sea-level, using ctrl to toggle canal or plain water tile. This allows building of non-raisable sea-level water ways (useful in multiplayer) and dikes for low-level areas (r5403) +- Feature: Add 4 new airports. 2 for aircraft, 2 for helicopters (r5346) +- Feature: Implement smooth horizontal depot and, vehicle list scrolling for trains (r5046) +- Feature: Add new pathfinder, YAPF. Has greatly improved performance and better, fully configurable, pathfinding (yapf) (r4987) +- Feature: Add a new console command 'players' that lists current players along with basic stats [FS#150] (r4828) +- Feature: Station List View can now be sorted and filtered (by waiting cargo type and facilities) (r4822) +- Feature: The integer-list parser now accepts a space character as an item separator next to the comma for openttd.cfg (r4490) +- Feature: Add support for electric railways as a separate tracktype. Electric trains will not run on non-electrified track unless otherwise controlled by patch option (elrails) (r4150) +- Feature: A new multi-lingual multi-measuring-unit system (r4126) +- Feature: Add proper OPENTTD <> LOCALCODE conversion using iconv. Savegames with special characters will be legible in filesystem (r4105) +- Feature: Undraw the mouse when it leaves the window and draw it again when it enters (r4075, r4083) +- Feature: It is now possible to turn a single unit in a train (CTRL+Click on unit in depot) (r3944) +- Feature: Delete news items about vehicles when they get stale (r3757) +- Feature: Save patch settings with the savegame so you are presented with the same behaviour when loading the game on another machine/installment (r3726) +- Feature: Add 2cc (two company colours) livery schemes. This replaces the original colour selection window (r3717, r6455) +- Feature: [OSX] Added support for triple binaries (binaries optimised for G3, G5 and i686) (r3674) +- Feature: Allow autoreplacing of train wagons (r3535) +- Feature: Allow sorting of vehicle lists by model or value (r3528) +- Feature: Allow trains details view to be resized (r3521) +- Codechange: Improve the usability of the signal-dragger, do not bail out at (certain) errors, just silently ignore them [FS#149] (r7127) +- Codechange: Make the zoom in/out buttons of the extra viewport into proper push-buttons (r7078) +- Codechange: Make the AI choose road vehicles based on a rating (currently max speed * capacity) instead of either the cost or the index of the vehicle (r7070) +- Codechange: Truncate text in window captions to prevent overflow (r7058) +- Codechange: Allow standard ini-file style comments (;) (r6972) +- Codechange: Send server messages with format NETWORK_ACTION_SERVER_MESSAGE so it is general colour like the rest of the server messages. Spectators speak in grey (r6932) +- Codechange: Change textmessage format a bit. Only the sender's name and target are in the sender's colour, the actual message is in white. Should improve readability (r6932) +- Codechange: Add an MD5 sum check of our own data files, and warn if they do not match (r6921) +- Codechange: Add strict bounds checking in string formatting system to check for possible buffer overflows (r6884) +- Codechange: Have the dropdown menus fall fully inside the top toolbar (r6745) +- Codechange: Determine the length of the main toolbar dropdown list based on the length of the strings in that list (r6744) +- Codechange: When vehicles never expire they will stay at peak reliability instead of the lowest to make them useful even when old (r6681) +- Codechange: Show more correct capacity of articulated wagons in the train purchase list (r6650) +- Codechange: When showing tooltips, properly position the tooltip taking into account window dimensions and cursor (r6405) +- Codechange: Speed up the animated cursors a bit so they move once in a while at least (r6367) +- Codechange: Remove the 'unsorted' vehicle sorter, because it is plain useless (r6270) +- Codechange: Remove MSVC6 support. The compiler was too stupid and too many workarounds were needed. Please switch to mingw or VC2005++ express (r5286) +- Codechange: Allow a switch in Makefile.config to disable threads in OpenTTD (r5978) +- Codechange: [Windows] Add native x64 target to VS2005 project files (r5813) +- Codechange: [Windows] The exception dialogue showed the last modification-date of win32.c instead of the last compilation-date (r5801) +- Codechange: Add owner attribute to canals and locks. This makes them more useful in multiplayer games, as only the owner can delete them. Does not affect usage (r5084) +- Codechange: [Windows] Add MSVC2005 support, project and solution files are in the _vs80.* files (r4581) +- Codechange: [OSX] Shark (Xcode's profiling tool) can now relate CPU usage to lines (r3611) +- Codechange: Rewrite the multistop slot assignment system. More resource-friendly, several slot-assignment improvements (r3730, r4259) +- Codechange: Completely remove the deprecated -p parameter (is superseded by -n) (r3508) +- Fix: Town ratings were not reset when a company went bankrupt (r7433) +- Fix: With realistic acceleration, guarantee a minimum braking force is applied. This ensures trains will stop when going down hill (r7425) +- Fix: Changed 'kick off' acceleration resulted in only a small amount of power being applied; this resulted in a perceived delay before trains moved (r7421) +- Fix: Long delay for message windows to appear. Immediately show a new message if present if no news window is open, or has just been closed instead of waiting for the timer of the current news to time out [FS#255] (r7402) +- Fix: Deleting Train in depot with autoreplace fails [FS#418] (r7385) +- Fix: Do not update vehicle images when turning a train around. During this procedure the train is split into parts which can result in incorrect images being used (r7378) +- Fix: OpenTTD could crash under certain circumstances when a vehicle as autoreplaced and a news window was open [FS#332] (r7368) +- Fix: Segmentation fault in the SDL video driver when one goes to fullscreen and there are no suitable resolutions (r7332) +- Fix: When loading a game from a dedicated server the local player set to 0, theoretically enabling the dedicated server to also play (r7312) +- Fix: TTDPatch vars are little endian (r7282) +- Fix: Always display the excavation of roadworks even when fully zoomed out or 'full details' are off (r7240) +- Fix: Window allocation and deletion messed with the actual window pointer, possibly crashing OpenTTD [FS#350, SF#1560913] (r7205) +- Fix: Callback not executed for non-player based patch changes in multiplayer for all clients; possible desync issue (r7190) +- Fix: Station sign (and base station coordinates) did not move along with station when station moved by walking [FS#388] (r7169) +- Fix: MiniMap was misplacing vehicles sometimes [FS#402] (r7166) +- Fix: Some mouse events possibly lost under high CPU load, handle mouse input right away instead of waiting for GameLoop [FS#221, SF1168820] (r7157) +- Fix: Some keyboard events possibly lost under high CPU load, handle keyboard input in place instead of global variables magic [FS#279] (r7153) +- Fix: 'Position of Main Toolbar' option is not honoured when starting new game or loading saved [FS#172] (r7130) +- Fix: Synchronise the engine-renew settings of a player when joining a multiplayer game (r7126) +- Fix: Several errors/glitches related to multiplayer and bankruptcy (mainly server), and non-updated company-information (r7125) +- Fix: Cloning a vehicle that has been refitted would incur the expense as running costs, not new vehicles [FS#371] (r7115) +- Fix: Do not let ships enter partial water tiles under bridges; they will travel up land... (r7110) +- Fix: AI tried to build road from the back or side of road stop/depot (r7069) +- Fix: Zooming out near map-borders would previously fail because the new centre would be outside the map [FS#317] (r7047) +- Fix: 'Goto' button in orders window got depressed along with all other buttons when an existing order was modified [FS#311] (r7046) +- Fix: Scenario bridges/tunnels cannot be demolished [FS#200] (r7028) +- Fix: Pressing F1 in scenario editor did not work (r7023) +- Fix: Properly guard against viewing company-sensitive information from invalid players (eg spectators) which could lead to crashes [FS#292] (r7022) +- Fix: In the replace vehicle window, the left vehicle list was not drawn when an engine was not selected (r7009) +- Fix: Crash at game end when server company is bankrupt [FS#369] (r7008) +- Fix: List of actions panel in the town authority window went underneath its scrollbar (r6885) +- Fix: Pressing ^D (EOF) at a dedicated console caused it to repeat the last command, instead of doing nothing (r6835) +- Fix: Do not add up running cost of articulated engine parts (r6765) +- Fix: If a rail is not available, do not show toolbar even with hotkey 'A' (r6740) +- Fix: Only apply the virtual transfer profit if the order is a transfer order, rather than to any unload order (r6738) +- Fix: Disable main toolbar buttons showing company list drop downs when there are no companies [FS#356] (r6695) +- Fix: Autoreplace can now use the money for selling the old vehicle to build the new one (r6640) +- Fix: A loop-hole that allowed docks to be built regardless of town authority rating (r6477) +- Fix: [Windows] The dedicated server could overwrite the keyboard input buffer before it was handled by OpenTTD (r6449) +- Fix: Reset the location of the last sound as that location can be outside the map when you are loading another, (smaller) map (r6437) +- Fix: Show an error message when executing 'scrollto x' with x < 0 or >= MapSize() instead of asserting later on [FS#340] (r6435) +- Fix: Station catchment area persists after switching tools [FS#136] (r6368) +- Fix: Do not reset the current cursor action when centring on a depot/hangar (r6360) +- Fix: Go to hangar orders for aircraft could get spuriously removed when a road or rail depot got deleted (r6355) +- Fix: Due to some off-by-one errors the width or height of a clipping rectangle could become 0, which is not sensible. This should fix a very rare and hard to trigger assertion in GfxFillRect() (r6351) +- Fix: Never allow scrolling the map in the main menu (scroll-settings were not reset if switched to mainmenu) (r6037) +- Fix: Never set I-am-a-thread bool to true IN the thread, dual-core machines could flip [FS#78] (r5977) +- Fix: Town-growth removed houses under construction to make way for road; unwanted behaviour [FS#49] (r5970) +- Fix: Cloned toad vehicles are not refitted to correct cargo [FS#275] (r5917) +- Fix: Bugfix for errors in FindNearestHangar function in aircraft_cmd.c [FS#235] (r5914) +- Fix: Sort order for produced amount and transported percentage was reversed in the industry list (r5912) +- Fix: Changing patch settings through the console did not accept on/off or true/false [FS#170] (r5903) +- Fix: Differing price calculation for tunnels depending on starting point [FS#253] (r5901) +- Fix: Goto sepot not always working for road vehicles [FS#249] (r5898) +- Fix: Bus trying to service in depot of other company [SF1519167] (r5897) +- Fix: If vehicles break down and service is turned off, the vehicles failed to enter any depots; now they will quickly go to a depot if set to be replaced (r5888) +- Fix: Incomplete removal of player owned property due to lack of money [FS#273] (r5886) +- Fix: < > boxes in patch-settings did not grey out when they hit the limit of their range (r5714) +- Fix: Check the configuration file for valid values and clamp them to their ingame minimum/maximum [SF1288024] (r3726) +- Fix: Remove the restriction that the 'patch' console command can only be run from network games [SF1366446] (r3723) + + +0.4.8 (2006-08-12) +------------------------------------------------------------------------ +- Fix: A ship in a depot must be stopped before it can be cloned +- Fix: After changing directory in 'Play Scenario', the default scenarios did not show up in 'New Game' + + +0.4.8-RC2 (2006-07-31) +------------------------------------------------------------------------ +- Feature: Add Italian town names as we have an official Italian translation +- Codechange: Verify the presence of music files in the gm/ folder. This should also solve some 100% CPU buildup for some users +- Fix: Certain combinations of trains crash when moved around inside the depot +- Fix: Reversed arrow-sign in the multiplayer list column headers on sort by name +- Fix: Industry production change button does not work for oilrig passengers +- Fix: Helicopters stopping in depot after autorenew/autoreplace +- Fix: MorphOS crashes when you go a level up in the root level +- Fix: UDP sockets were used even if network-availability was set to false +- Fix: Crash when trying to build a vehicle type that is set to a max of zero + + +0.4.8-RC1 (2006-06-28) +------------------------------------------------------------------------ +- Feature: Add Turkish town names as we have an official Turkish translation +- Feature: Add a fully optional configure script that is a wrapper around the cumbersome makefile.config +- Codechange: [NPF] Disable NPF totally for ships as it wholly kills performance. Only for 0.4/ branch and 0.4.8 +- Fix: Redraw the screen when switching the signal side in the patches window +- Fix: It was possible to dig into a tunnel if certain rail combinations were on top of it +- Fix: A HQ could only be flooded at its northern tile, the other 3 were immune to water +- Fix: Fix several glitches concerning foundations. Houses, property (rail/road/bridge/etc.) and cursor are now aligned properly +- Fix: Prohibit altering a road tile while road works are in progress. This fixes some glitches like 'turning' the excavation by adding/removing road bits or removing the road piece +- Fix: Only advertise the server to your external IP/network (eg not to 127.0.0.1) and use proper broadcast addresses +- Fix: '-f' switch is not valid on windows, so do not show it in help +- Fix: [Autoreplace] Autoreplaced trains can leave all wagons in depot under certain circumstances +- Fix: The wrong IP could get unbanned, e.g. 'unban 1.2.3.42' could result in unbanning 1.2.3.4 +- Fix: It was possible to convert the railtype of a bridge while a train was on it +- Fix: It was possible to rename signs or waypoints with the chat box +- Fix: Be more strict what it means for an aircraft to be in a hangar: It is not just being stopped on a hangar tile +- Fix: If a road vehicle is on a road depot tile and stopped does not mean it is in the depot. Use the proper test for this +- Fix: [AI] The AI should send a plane into a hangar if it is not in a hangar _or_ not stopped, not when it is not in a hangar _and_ not stopped +- Fix: [AI] The trolly AI used information from the wrong industry when calculating the amount of to be transported goods +- Fix: [NTP] Fix NTP over bridges: do not check the rail type when on a bridge +- Fix: Truncate text in dropdown lists to stop text overflowing +- Fix: 'Erroneous train reversal on waypoints'. When processing the next train order, do not even consider reversing the train if the last order was to a waypoint +- Fix: Starting a new scenario did not adhere to local difficulty settings but took it from the scenario itself. That mode is for 'play scenario' +- Fix: Vehicles on a sloped tile under a bridge were affected by the bridge speed limit +- Fix: Issue with train pathfinding over level crossings +- Fix: [AI] The AI no longer attempts to build signals under bridges +- Fix: Refresh build vehicle window (if opened) when converting rail depot +- Fix: Crash when sorting an empty server list +- Fix: The build-tree window button defaulted to a place-push-button on opening where no treetype is selected +- Fix: Game crashes when cloning/autoreplace reaches train-limit +- Fix: [NTP] Properly check for railtypes on non-plain-rail-tiles +- Fix: Trains could enter certain sloped rail tiles under bridges with incompatible rail type +- Fix: Ensure the map memory is cleared after it is allocated. This fixes random deserts that sometimes occurred +- Fix: Some weird behaviour with tile selection near bridges +- Fix: Do not allow PF to enter train depot from the back (signal updates) +- Fix: Game no longer crashes when the last vehicle servicing a station has been deleted +- Fix: Reset the last built railtype when starting a new game +- Fix: Cloned vehicles get the same service interval as the original vehicle +- Fix: Game no longer errors out when 'Many random towns' is selected in the scenario editor +- Fix: Obscure road dragging bug. The road build command did not return the appropriate error message of invalid-slope when building road +- Fix: Temperate bank will no longer appear (during game) in tropic landscape. This bug is from the original game +- Fix: Specify the 'stopall' console command as a debug command +- Fix: Fixed a problem that caused DeliverGoodsToIndustry to not work as intended +- Fix: Ships and aircraft can now be used as feeders as well +- Fix: When a multiheaded train is sold the pointers were not updated correctly causing sporadic crashes/disconnects +- Fix: New plantations now cause the correct '.. being planted ..' news item +- Fix: Danish town names were saved/loaded as Swiss +- Fix: Removing roads on crossings was done without a check for ownership +- Fix: [Autoreplace] Fix drawing of train list for outdated engines +- Fix: Malicious clients/servers could crash the game [CVE-2006-1999, CVE-2006-1998] +- Fix: [Autoreplace] Allow replacement of wagons even when the engine fails to be replaced +- Fix: Certain operations involving trains inside a depot could cause a crash +- Fix: [Autoreplace] Cost for refitting a new vehicle is added to the cost animation (player always paid for it, it just was not shown) +- Fix: [OSX] Save/Load issues solved for OSX 10.3.9 universal binaries +- Fix: Illegal servers in the master-server list could kick the client back to the main menu, effectively making Multiplayer impossible +- Fix: [NPF] Do not mark tiles when debugging in multiplayer, this will cause desyncs +- Fix: Several fixes to chatbox code, mainly plug a buffer overflow + + +0.4.7 (2006-03-26) +------------------------------------------------------------------------ +- Feature: [OSX] Add support for triple-binaries (PPC, PPC970, i386) (r4102) +- Fix: [OSX] Crash when going to fullscreen (r4100) +- Fix: Allow unused wagons to have their first cache set. Fixes faulty cache-warning message and noticeably speeds up depot operations (r4094) +- Fix: [NPF] Trains & buses were unable to find a route when leaving a depot or bus stop (r4072) + + +0.4.6 (2006-03-22) +------------------------------------------------------------------------ + +- Codechange: [Windows] Show the revision in crash.txt and enable the button to show the crash text in the crash-window (r3965) +- Codechange: Add additional linker information to release builds to help figure out crashes more easily (r3526) +- Fix: [OSX] Cannot save game if name contains german umlauts (loading savegames with certain chars still look odd) [SF#1157244] (r4038) +- Fix: [OSX] Major speedup for PPC fullscreen (r4034) +- Fix: [Makefile] Make sure the ICON_DIR gets created before copying files there (r4032) +- Fix: [Windows] Change compiler settings to use the multithreaded CRT. This prevents certain crashes on multi-threaded machines (r4031) +- Fix: [NPF] Road vehicles planning through the back of depots and stations [SF#1453646] (r4029) +- Fix: Use the title of a savegame in the saveload dialogue-editbox (r4018) +- Fix: Improper resolution written to the configuration file when exiting from fullscreen (r4017) +- Fix: When removing rail track from a tile where only X and Y pieces exist, explicitly update signals in both directions (r4016) +- Fix: Default the patch-setting 'pause_on_join' to true (r4015) +- Fix: Slope and height information returned for some tile types is wrong (r4014) +- Fix: Fixes a bug introduced by r3228 which allowed steep rail tiles resulting in ... unwanted effects such as display artifacts (r4012) +- Fix: Update french translation (r3978) +- Fix: Missing glyph(s) in big-font. Added several missing glyphs for the big font [FS#56] (r3970) +- Fix: Increase client list window width so at least most languages fit [SF#1439907] (r3969) +- Fix: Update german and finnish languages (r3968) +- Fix: Properly set back the owner of a crossing/road-under bridge after removing it (r3967) +- Fix: [Autoreplace] Autoreplacing trains now keep their tile length instead of their pixel length [FS#67] (r3964) +- Fix: Mark the right tile as dirty. It is just a graphical glitch which happened in r1592 (r3962) +- Fix: Fix crash when resizing news history window (r3961) +- Fix: Correctly implement minimum search, so road vehicles head towards the closest station, not the last one in the list (r3960) +- Fix: The tooltips for raising and lowering land buttons in the scenario editor are interchanged [FS#61] (r3959) +- Fix: Correctly restore the roadside after roadworks are finished (r3957) +- Fix: [Multistop] Check the status of the destination road stop instead of a station's first road stop. This only has effect with road vehicle queueing disabled (r3956) +- Fix: Validate the setting of max_companies/spectators through the console (r3955) +- Fix: Improve game-load times (r3954) +- Fix: On loading a game, GetPlayerRailtypes() did not account for the fact that vehicles are introduced a year after their introduction date. This will also relieve possible (rare) network desyncs (r3952) +- Fix: Restore plural forms of cargo types for several languages (r3951) +- Fix: [Windows] Add directives to allow Visual Studio 2005 compilation (r3950) +- Fix: Crash in string code with openbsd/zaurus; alignment issues [SF#1415782] (r3948) + + +0.4.5 (2006-01-31) +------------------------------------------------------------------------ +- Feature: [NewGRF] Implement varaction2 property 0x41 and 0xDA (r2361) +- Feature: Giving server_ip a value of 'all' will make the server listen on any interface (r2374) +- Feature: Shortcut CTRL + U that clears the current input-box (r2385) +- Feature: [NewGRF] Implement the mechanism for handling NewGRF callbacks (r2389) +- Feature: [NewGRF] Implement the 'refit capacity' callback (r2389) +- Feature: Saving games happen in a separate thread (r2391) +- Feature: [NewGRF] Implement powered wagons, and the callback that goes with it (r2414) +- Feature: [NewGRF] Implement shorter train vehicles (r2428) +- Feature: New display option: 'transparent station signs' (r2438) +- Feature: You can now give transfer order to set up feeder systems (r2441) +- Feature: Removing tracks with the 'remove' tool, automatically removes signals on the tracks (r2469) +- Feature: [Localisation] Allow changing the order of parameters in translated strings (r2573) +- Feature: [Localisation] New way to specify plural forms (r2592) +- Feature: [Localisation] Support genders (r2594) +- Feature: [Localisation] Support cases (r2597) +- Feature: Add support for truncating strings to a given (pixel) length (r2607) +- Feature: Overhaul DirectMusic MIDI backend, remove 'experimental' status (r2712) +- Feature: Change the driver probing algorithm: Use the first music/sound/video which succeeds initialising instead of bailing out after the first. No need to specify -snull if no soundcard is present anymore (r2728) +- Feature: The Main Toolbar Dropdown Menu can now display disabled items (r2734) +- Feature: Clone vehicles (r2764) +- Feature: When starting without a config file determine the language on basis of the current locale (r2777) +- Feature: [NewGRF] Add support for 'extended bytes' (r2872) +- Feature: [Localisation] Major step towards ISO-8859-15: Implement missing characters (r2879) +- Feature: Implement the console command rm to remove savegames (r2941) +- Feature: Danish town names (r2957) +- Feature: Menu option to toggle console (r2958) +- Feature: Calculate proportions of non-square giant screenshot correctly (r2963) +- Feature: [NewGRF] Implement current set of action D (ParamSet) operations (r2968) +- Feature: [NewGRF] Show a wagon's speed limit in purchase list (r2969) +- Feature: [NewGRF] Support loading VarAction2 parameter for variables 0x60-0x7F (r2971) +- Feature: [NewGRF] Add patch option for wagon speed limits (r2982) +- Feature: [NewGRF] Support loading of bridge attributes and tables from GRF (r3004) +- Feature: Native Support for Win64 (r3008) +- Feature: OSX now uses quicktime to play midi files (r3022) +- Feature: [OSX] Command+Q now works in main menu (r3027) +- Feature: Allow unbanning players based on banlist-id (as well as IP) (r3067) +- Feature: 'status' and 'clients' now show the IP of the players (r3067) +- Feature: Make it possible to create a screenshot from the console that is both big and has no console, or any combination of (r3068) +- Feature: [NewGRF] Add support for rail vehicle weight greater than 255 tons (r3071) +- Feature: 'HOME' icon to saveload dialogues that jumps to the default save/load directory based on the dialogue (r3096) +- Feature: Turkish translation (r3120) +- Feature: [NewGRF] Support positioning of rail vehicle visual effects (r3132) +- Feature: [NewGRF] Support for articulated rail vehicles (r3139) +- Feature: [NewGRF] Add support for cargo refitting specification by cargo classes (r3148) +- Feature: [NewGRF] Action 7/9 new value : is it TTDPatch or OpenTTD? (r3152) +- Feature: Drag and drop rocky areas in scenario editor (r3153) +- Feature: Added patch option to link the terraform toolbar to the rail, road, water and airport toolbars (r3157) +- Feature: Right-Click-Scrolling optionally moves in the opposite direction (r3222) +- Feature: Native cocoa sound and video drivers for OSX (r3281) +- Feature: [NewGRF] Allow train running cost class to differ from engine class (r3388) +- Feature: Kick and ban now with IP numbers (r3407) +- Feature: Allow seeing and setting the maximum amount of companies and spectators for a server. This can be changed/viewed during runtime as well in the console (r3427) +- Feature: Allow the network game list to be sorted (by name/clients/compatibility ascending/descending) (r3441) +- Feature: Make it possible to ban offline clients (r3469) +- Fix: The refit window now shows the correct refit options (r2365) +- Fix: Refitting to a cargo which is already carried by some vehicles takes their capacities into account for display (r2365) +- Fix: Add 'multihead' TTDPatch option to OpenTTD NewGRF flags-emulation (r2368) +- Fix: Make install tried to install scenarios in the (non-existing) personal dir when USE_HOMEDIR is specified (r2371) +- Fix: [Console] Update the example scripts in the scripts/ directory to reflect the new console functionality (r2372) +- Fix: [Console] Any line starting with a '#' is a comment so ignore it (r2372) +- Fix: [Console] The special variables whose value can only be set by a custom process should, also print out their newly set value there (r2372) +- Fix: [NewGRF] Ignore action 0 prop 0x20 (air drag) (r2377) +- Fix: [NewGRF] Further property stubs, help prevents subsequent incorrect reading of NewGRF data (r2378) +- Fix: Build year for mail compartment of planes was not set correctly, affected station ratings (r2380) +- Fix: Endgame window on easy difficulty resulted in infinite loop (r2381) +- Fix: Check the airport type when building an airport (r2382) +- Fix: Monkey-testing turned up some command crashes (r2383) +- Fix: Check selling land and setting player colour. Also an extra map-bounds check for terraforming (r2384) +- Fix: [Realistic acceleration] Very slow trains no longer get an increase in maximum speed when part of them is in a depot (r2388) +- Fix: [NewGRF] Load power for dual-headed engines correctly (r2400) +- Fix: [NewGRF] When resolving callbacks, don't ignore wagon overrides (r2410) +- Fix: Station ratings are not affected by speed limits from realistic acceleration anymore (r2411) +- Fix: Building vehicles without depot crashed the game (r2412) +- Fix: Certain resolutions caused a crash when minimap was partly dragged outside the game window (r2424) +- Fix: Deleting canals under bridges removed bridges first in certain configurations (r2436) +- Fix: [NPF] Vehicles try to drive into a tunnel entrance from above (r2471) +- Fix: [NewGRF] Some road vehicle action 0 properties were loaded as the wrong type (int8, int16, int32) causing undefined results, like cargo types being wrong (r2474) +- Fix: The console variable autoclean_unprotected was linked to the variable _network_autoclean_protected (r2498) +- Fix: Old bug in the PCX writer: The first pixel column contained garbage, the picture was shifted one to the right, and the last column was dropped (r2512) +- Fix: Using the mouse wheel could lead to a crash if mouse was not over a widget (r2530) +- Fix: Blinking 'lock' gfx in multiplayer games (r2548) +- Fix: Remove original train pathfinder. Enhanced old pathfinder (r2553) +- Fix: Spaces in the path to the MIDI files caused the Windows MIDI player to fail (r2563) +- Fix: Set server map name to the loaded name of the game/scenario (r2610) +- Fix: Improve the old pathfinder. Changed it to A* instead of Dijkstra. Benchmark shows that NTP is now around 10x faster than NPF (r2635) +- Fix: Correctly save and load company_value, it is 64 bits wide, not 32 bits (r2684) +- Fix: Volume control works now for the DirectMusic MIDI backend (r2712) +- Fix: Change the fence algorithm so it removes fences when no farm tile is adjacent (r2739) +- Fix: Tree tiles above the snow line got redrawn disproportionately often (r2750) +- Fix: Depots could build trains of the wrong track type (r2764) +- Fix: Sort the directories in the scenario/savegame list (r2860) +- Fix: On OS/2 show the trailing \ if the current directory is a root directory (r2860) +- Fix: Return a proper version number, when testing the TTDPatch version in the SkipIf action (r2862) +- Fix: Change the way NewGRFs are loaded, this saves quite some sprite slots - about 2000 for DBSetXL for example (r2868) +- Fix: Several format string vulnerabilities and buffer overflows in the network code [CVE-2005-2764, CVE-2005-2763] (r2899) +- Fix: Fixed issue where autorenewed vehicles did not get all stats updated (r2912) +- Fix: Exit the child of the extmidi backend with _exit() instead of exit(), because we do not want any atexit handlers - especially flushing output streams - to run, if exec() fails (r2938) +- Fix: Server crash with 'say'-command (r2950) +- Fix: Fix Windows midi volume level control which did not work (r2960) +- Fix: [OSX] Quitting the game no longer leaves a process behind that eats all the CPU power (r3281) +- Fix: Fix for UFO-broken waypoint [SF#1216203] (r2961) +- Fix: [NewGRF] Include missing grf feature canal +- Fix: [NewGRF] Add bounds checking to VehicleChangeInfo for vehicles +- Fix: [NewGRF] Wagon speed limits do not apply for wagons with livery overrides +- Fix: Align settings pool items to the size of void* to fix bus errors on 64bit architectures which require aligned variables (r2976) +- Fix: Restart_game_date is an UINT16, not a BYTE. Now setting the game restart year via the console should work (r2987) +- Fix: [NewGRF] Some GRF files do not specify a name or description, in which case the Action 8 is 8 bytes, not 9 (r3005) +- Fix: The finnish markka was never abbreviated with capital letters (r3021) +- Fix: Improve handling of non-existent sprite sets (r3044) +- Fix: Do not attempt to map and empty sprite group to a vehicle (r3045) +- Fix: Fixed typo and hang for BeOS Networking (r3053) +- Fix: On Win98 and lower when you go to the root directory of a drive (eg. C:\) you were stuck there indefinitely and could not change any directories or see any files (r3056) +- Fix: Complete rewrite of autoreplace; multiheaded train engines are replaced correctly (r3081) +- Fix: A new train is now made if the front unit is an engine and the former front engine is moved away (r3144) +- Fix: There are only 2 possible directions for ship depots, not 4 (r3199) +- Fix: Allow bribing up to the maximum rating for bribing, do not disable this option at some arbitrary value early (r3201) +- Fix: Do not lower land on tunnel, even with diag tracks on it (r3228) +- Fix: Crash when making a screenshot in the main menu (r3235) +- Fix: Crash when starting a scenario via 'New Game' fails (r3235) +- Fix: Determine clicked status of sticky icon from window flags rather than the widget click state (r3247) +- Fix: Graphical glitch with autorail tool on a certain tile-types (r3254) +- Fix: Centre the X of the window close button (r3302) +- Fix: [NewGRF] Unload engine names before loading grf files (r3316) +- Fix: Network window crash when it receives invalid information for example from the integrated nightly, so validate the network-input when it is received (r3322) +- Fix: Build failed if SDL is built without pthread support (r3326) +- Fix: Move initialisation of vehicle random_bits to DC_EXEC blocks to allow use of Random() instead of InteractiveRandom(), which will alleviate some possib le network desyncs (r3352) +- Fix: The default AI tried to change the service intervals of vehicles via the CMD_CHANGE_TRAIN_SERVICE_INT command - regardless of the type of the vehicle (r3367) +- Fix: Out-of-bounds array access when road vehicles overtook in a curve caused desyncs (r3371) +- Fix: Update signal states when building or removing rail station blocks (r3372) +- Fix: Do not allow trains to get bigger than 100 via drag and drop (r3374) +- Fix: Do not reset date in the scenario editor when pressing RandomLand (r3376) +- Fix: [NewGRF] Running cost should be halved for dual head vehicles (r3384) +- Fix: No fence was placed when placing fences and the neighbouring tile is a rail configuration which permits a fence but has a signal (r3389) +- Fix: [NewGRF] Ignore non-climate dependent cargo types (r3394) +- Fix: [NewGRF] Only add a random number of days to an engine's base introduction date if that date is not 0 (r3410) +- Fix: When changing the server password via the console, actually set the password as well as flag whether it is required (r3411) +- Fix: Under certain conditions placing a road tile parallel under a bridge would, instead of failing, succeed and place a perpendicular piece (r3413) +- Fix: Disable the Fund New Industry menu item and window when connected to a server as a spectator (r3414) +- Fix: Disable the clone and refit buttons in the train view when viewing another player's vehicles, or as a spectator (r3415) +- Fix: Disallow building an oil rig above sea level (r3416) +- Fix: When removing a town-owned tunnel the player's rating was not reduced (r3418) +- Fix: (Possible) game crash on removing track/road under bridge if a vehicle was on the track/road under the bridge and the track/road sloped (r3419) +- Fix: [NewGRF] Only power should decide whether a rail vehicle is an engine or a wagon (r3424) +- Fix: Incorrect validating of tree-planting command which can allow a buffer-overflow (r3446) +- Fix: [NewGRF] When changing the sprite ID of a vehicle, if it is not FD (custom graphics), the value needs to changed from a 16bit array offset to an array index (r3449) +- Fix: You could not remove an item from a list-type of config ingame from the configuration file (r3475) +- Fix: [NewGRF] Always reinitialise the TTDPatch flags as patch settings may have changed (r3486) +- Fix: Price for demolishing a bridge was dependent on orientation and map size (r3487) + + +0.4.0.1 (2005-05-21) +------------------------------------------------------------------------ + +- Feature: Add 'clear' command and CTRL+L to empty console window +- Feature: Add the possibility to print out the current debug-level +- Fix: [MacOSX] Default path for midi player on mac is now correct again +- Fix: Updated makefile for FreeBSD +- Fix: Text overflows in about box +- Fix: Link error while compiling as dedicated server +- Fix: Do not execute empty commands +- Fix: Make OpenTTD icon look good on Win2K and earlier +- Fix: NetworkUDPRemoveAdvertise was not completely correct +- Fix: Signs in multiplayer did not work +- Fix: Dedicated server desyncs +- Fix: Error: !invalid string id 0 in GetString, dedicated server endgame crash [SF#1197216] +- Fix: Do not allow things to be renamed to nothing +- Fix: Windows installer deletes spritecache files on uninstall +- Fix: Depot window did not get redrawn when a non-train-engine was sold +- Fix: Do not scroll the game with the arrow keys when the chatbox is open +- Fix: Remove warning from release build when assertions are no longer active +- Fix: It was possible to open more than one tree window + + +0.4.0 (2005-05-15) +------------------------------------------------------------------------ +- Feature: Bigger maps. Enjoy playing up to 2028x2048 (64 times as big as you were used to!) +- Feature: New realistic acceleration; should be much better. Includes bigger penalty on narrow curves and speedlimits in depots/stations +- Feature: It is now possible to build multiple road stations (up to 8) on a single station +- Feature: New PathFinder (NPF). Support for train/road and ship based on A*. No more braindead pathfinding +- Feature: Dynamic towns/industries/stations/vehicles/signs/orders/everything, up to 64K +- Feature: Brand new OldLoader so OpenTTD is TTD(Patch) compatible again. Also endian safe +- Feature: Even better NewGRF support, except for callbacks, everything works (ok, almost) +- Feature: Improved multiplayer. More console options, less desyncs and more fun +- Feature: Protected OpenTTD from interference of hacked clients, so it should be safe to play again +- Feature: Saving vehicle sorting criteria for each vehicle type [SF#1093261] +- Feature: Resizable orders GUI [SF#1107690] +- Feature: Focus keyboard on input-box in Multiplayer Menu [SF#1166978] +- Feature: Terrain hotkeys nonfunctional in scenario editor (D,Q,W,E,R,T,Y,U fltr) [SF#1174313] +- Feature: Complete rework of console and new commands like ls, save, load, help, etc +- Feature: Signs are shown in the colour of the player who created them +- Feature: Add cheat option to set production of raw-material industries in game +- Feature: Replace train GUI remembers railtype selected from the dropdown menu +- Feature: Improved Autoreplace +- Feature: Many more smaller features +- Fix: A wrong error message was displayed when trying to [SF#1108618] +- Fix: Game does not crash any more when a NewGRF file does not exist [SF#1110407] +- Fix: Clearing land for free by reallocating HQ [SF#1112469] +- Fix: Clearing land for free by reallocating HQ [SF#1112469] +- Fix: Crash when accessing hi-scores in editor, it is now disabled [SF#1113037] +- Fix: Game no longer crashes when right-clicking a disabled Full Load button [SF#1113399] +- Fix: Dedicated server boots again [SF#1114100] +- Fix: Game crashed sometimes when there were no industries in the map [SF#1114950] +- Fix: In the main menu, when starting a new game while the load game dialogue is open, openttd asserts [SF#1115200] +- Fix: Non-stop orders are no longer accidentally skipped [SF#1117538] +- Fix: Generate the correct smoke type for diesel trains [SF#1116619] +- Fix: Max passengers/mail variables are now 32 bit [SF#1119308] +- Fix: Better test if a string actually contains any console command [SF#1109400] +- Fix: 'Play scenario' now loads game options and difficulty, 'Load game' starts game with user-selected values [SF#1108637] +- Fix: Carriages of NewGRFs can be refitted again [SF#1143587] +- Fix: Production values of temperate-climate banks can now be altered [SF#1117730] +- Fix: Mapwrap fixed in ship_cmd.c (was implicitly ok before biggermaps) [SF#1118810] +- Fix: Assertion error on kick. When a company is cleaned all its windows need to be closed. For global vehicle lists, the no-station index of -1 was not taken into account [SF#1117327] +- Fix: Speeding up when pressing ALT+TAB (Windows) [SF#1114261] +- Fix: Signals disappear after typing text and pressing enter!. Signs in Scenario Editor have no owner so ignore that [SF#1149403] +- Fix: Single tile Bridge in Volcano City scenario. Some bridges still had the old single-tile bridge bug that was caused by improper town growth in combination with DC_AUTO. Fixed the scenario [SF#1149766] +- Fix: Stop startup memory corruption crash using optimised MSVC6. MSVC6 workaround as it is too stupid again for its own good [SF#1119147] +- Fix: Dedicated server now accepts '-g' (load game) as param [SF#1101874] +- Fix: Crash with German umlauts in station names [SF#1155696] +- Fix: Segmentation fault when loading savegame, out of bounds array check [SF#1158618] +- Fix: Autosave ignoring settings [SF#1149487] +- Fix: [Windows] Infinite access for A:\. Only requery drive(s) if the user changes a directory, also suppress the OS error box that pops up on some windows machines [SF#1024703] +- Fix: Create Lake and draggable Create Desert tools [SF#1095110] +- Fix: Trains 'Go to depot' button: click twice skip to next order [SF#1172878] +- Fix: Engine power not updated w/auto replace' autoreplace now forces an update of the cache [SF#1146215] +- Fix: [Windows] Path displaying as 'C:\\' [SF#1173690] +- Fix: Click & drag removal of road assertion fail [SF#1179892] +- Fix: Max loan always in euros, use _opt_ptr instead of _opt [SF#1174237] +- Fix: AI orders its vehicles to a competitor's truck stop [SF#1184201] +- Fix: Song in main menu screen should loop when it ends [SF#1188986] +- Fix: Non-existing sprite #5125 (presignal). The DOS grf file trgi.grf has 6 less sprites than the windows one [SF#1188777] +- Fix: Changing mapsize crashes game with highlighting [SF#1190625] +- Fix: [NPF] Trains ignoring their railtype (mono, maglev) [SF#1190896, SF#1184378] +- Fix: Clicking ship list on buoy asserts GetPlayer() [SF#1202115] +- Fix: No HQ present for competitor, disable 'View HQ' button [SF#1187613] +- Fix: Pre-signal stays red when there is only a single exit signal [SF#1193048] +- Fix: Train in tunnel is not properly detected by signal code [SF#1185176] +- Fix: [NewGRF] Rotors of custom helicopters are displayed correctly in the hangar window +- Fix: Scenario Editor now handles human-made roads better (try to build a city layout before placing the city, finally that works very nice) +- Fix: [NewGRF] Helicopters are correctly recognised +- Fix: [Autoreplace] Made sure that planes only show planes in replace GUI and helicopters only show helicopters +- Fix: Crash when generating tropical maps +- Fix: [Autoreplace] Cheaters can no longer exploit autoreplace to get vehicles, that is not invented yet +- Fix: [Autoreplace] Fixed a stupid bug introduced in r1687, that made a crash if anybody tried to autoreplace anything but an aircraft +- Fix: Expand rail stations beyond maximum spread +- Fix: [Autoreplace] Fixed a typo that could prevent autoreplaced aircraft from automatically go to a hangar +- Fix: Hacked clients can no longer be used to build vehicles that are not available yet +- Fix: Minimum profit of vehicles was calculated wrong for Performance Rating +- Fix: No longer a station where you only unload is bad for your town-rating +- Fix: Crash in scenario-editor with terraforming out-of-map bounds +- Fix: Game would crash if you full-screened with the 'fullscreen' button than chose a resolution from the dropdown box that was no longer valid +- Fix: Scrolling with the arrow keys is now smooth and it now also scrolls exactly in tile direction if e.g. up and left are pressed + + +0.3.6 (2005-01-24) +------------------------------------------------------------------------ +- Feature: Resizeable windows. All useful windows are already made resizeable +- Feature: Highscore chart (accessible from the difficulty window) with top 5 companies for a given difficulty (select the difficulty in the menu) +- Feature: Endgame score on 1 Jan 2051 where you are added to the highscore if sufficiently large points have been accumulated. Game is paused while +- Feature: Visually enhanced autorail placing +- Feature: Autoreplace Vehicles (accessible from the vehicle lists) +- Feature: A counter to tell how many engines you have of each type to the autoreplace vehicle windows +- Feature: A display for the total map population to the town display +- Feature: [Network] RCon (Remote console) +- Feature: Hotkeys for dock and airport toolbar (see http://wiki.openttd.org/index.php/Hotkeys) +- Feature: [Network] Banning system (mostly tnx to guru3) A server can ban people via ClientList using 'ban', 'unban', 'banlist' +- Feature: [Network] Server can now pause and unpause a game through the console. Use 'pause' and 'unpause' +- Feature: [OS/2] OS/2 support is now finished (Fixes for networking, file selection, keyboard input, plus many other minor issues) +- Feature: [SDL] Show revision number in window title +- Feature: [Unix] Check which gcc version is present and only set available compiler flags +- Feature: [Windows] CTRL+V (Paste) now works on all editboxes. This includes 'Add Server', chat, etc +- Feature: [Windows] Dedicated server is now functioning correctly +- Feature: Added keyboard shortcuts for the order window +- Feature: Aircraft refit options have been restricted to 'sane' values +- Feature: Allows setting the production values of the raw material producing industries in the editor +- Feature: Console support for loading maps. Use 'load', 'list_files' and 'goto_dir' to navigate and load games +- Feature: Display server port in the multiplayer game info window +- Feature: Dynamite in landscaping toolbar (hotkey 'D') +- Feature: Improved Network Lobby GUI with a green dot if company income is positive (else red dot) and lock icon if company is password protected +- Feature: Make OpenTTD compile on Zeta +- Feature: MD5 hash check for TTD files +- Feature: New companies receive a 5-year protection period against buying-up +- Feature: Norwegian townnames +- Feature: Order Checking is only execute for ONE vehicle in an order-share system +- Feature: Passengers aircraft now ignore the amount of mail for 'full load any' options +- Feature: Place multiple accepting industries nearby in the editor mode if the appropriate patches are set +- Feature: Population in label of the town (patch setting) +- Feature: Scrolling credits list (in alphabetical order) +- Feature: Train window now shows the number of vehicles per row +- Feature: Swiss town-names [SF#1039061] +- Feature: Adding 16:10 resolutions for mainly laptops [SF#1090950] +- Feature: (dis)Allow Shares. Add patch options to allow buying/selling of shares [SF#1098254] +- Add: A brand new set of icons +- Change: AutoRenew is now a client-side patch instead of a game-side patch +- Change: Removed the 'close ALL windows' from the toolbar since shift+del does this +- Fix: Catchment area shows when buying sign [SF#1031451] +- Fix: Flood and wagons in depot [SF#1040119] +- Fix: Buying trains sometimes accounted for incorrectly [SF#1050990] +- Fix: Delayed news messages [SF#1084074] +- Fix: Slopes under high bridges were not flooded [SF#1090495] +- Fix: In scenario editor, when trees are placed randomly, they are no longer placed on farmland [SF#1092473] +- Fix: On create, the scrollbar of the server-list was not updated [SF#1092661] +- Fix: Placing rocks in scenario editor. You can place rocks on trees and vice versa [SF#1092707] +- Fix: Drive side in new games. Setting the driver side is possible during the game until someone buys road vehicles. In networked games only the server can change it [SF#1093200] +- Fix: No more glitches with many maps in the scenario list when creating server [SF#1093466] +- Fix: Disappearing rocks in Scenario Editor [SF#1093485] +- Fix: Toolbars accessible via keyboard in spectator mode [SF#1094092] +- Fix: When all stations in an aircraft's order list are demolished, the plane eventually crashes (running out of fuel) [SF#1095020] +- Fix: Servers list now also saves the port [SF#1095143] +- Fix: Crash when all vehicles from a vehicles per station list had been removed [SF#1098553] +- Fix: Starting year patch goes out of range. Clamped year between 1920-2090 [SF#1099101] +- Fix: Bug Fix - Vehicle Lists not updated at Acquisition [SF#1099225] +- Fix: Game crashes after the click on Rename (see also Bug 10992). There was no check for non-selected engine [SF#1099451] +- Fix: Wrong tooltip for place desert button [SF#1100736] +- Fix: Fast forward in main menu [SF#1100767] +- Fix: Crash if generating land while industry window is open. This also happened for towns and the land information window [SF#1101179] +- Fix: Configure Patches window text overflow [SF#1101906] +- Fix: Console in dedicated server [SF#1101963] +- Fix: Game crashed when clicking 'new face' or 'company colour' twice [SF#1102275] +- Fix: Vehicle lists are now redrawn when a vehicle arrives in a depot. Station-specific vehicle lists are now redrawn daily as well (not only the master list) [SF#1099535, SF#1102776] +- Fix: Font size changing. Dedicated server did not have code filtering, 'tab' could result in bigger fonts [SF#1103113] +- Fix: Order Check messages are now validated before displayed [SF#1103187] +- Fix: Rail road tracks on slopes were not flooded [SF#1103301] +- Fix: Crashed trains do not initiate the lost vehicle message anymore [SF#1104350] +- Fix: On horizontal/vertical tracks you are also charged for building/removing signals on the parallel track on the same tile [SF#110452] +- Fix: Aircraft in hangar messages are now revalidated before display [SF#1104969] +- Fix: Destroyed train locks crossings [SF#1105112] +- Fix: Upgrade rail fails when train under bridge [SF#1105281] +- Fix: Trains do not think they are on a slope any more while they drive around in a tunnel [SF#1105959] +- Fix: Buoys can now only be removed if no ship has it in their schedule. This makes buoys more usable in multiplayer games again, as buoys cannot be deleted by other players if they are used [SF#1105963] +- Fix: Graph's keys get confused [SF#1106354] +- Fix: Placing signals with 2x1 drags is treated as placing a single signal [SF#1106930] +- Fix: Console ignoring return character occasionally [SF#1107350] +- Fix: Scenario creation bug; engines are of correct year when scenario is saved [SF#1108008] +- Fix: Little red box in scenario editor [SF#1092474] +- Fix: Scrolling through console sometimes crashed the whole game [SF#1099197] +- Fix: Catchment area with drag&drop stations [SF#1099209] +- Fix: [Network] 'kick 1' did crash dedicated servers +- Fix: [Network] A server no longer crashes when a client sends an invalid DoCommand, but drops the client instead +- Fix: [Network] Added packet protection. No longer a client or server +- Fix: [Network] Bug in bind system. Advertising failed on systems with more than 1 ip, and server_bind active to one of them +- Fix: [Network] Disabled 'money-cheat' (read: bug which could give people a lot of money) +- Fix: [SDL] Now the binary never links to SDL if DEDICATED is set +- Fix: [Windows] Somehow mousewheel was disabled on windows using SDL; re-enabled again +- Fix: A modified client could try to replace a vehicle to an invalid engine ID and crash the server +- Fix: Autoreplace vehicle lists are now redrawn when a new vehicle becomes available +- Fix: Buy Vehicle GUI now shows HPs bigger than 32000 correctly +- Fix: Console alias, load_game functionality and load fix +- Fix: Correct error message for when trying to build a rail station over a bus/truck/etc-station +- Fix: Correct landscaping buttons in monorail and maglev toolbars +- Fix: Dedicated server also writes to log file if active +- Fix: Desert-landscape does no longer crash +- Fix: Expand town is a bit more aggressive +- Fix: Finally zooming in/out always works +- Fix: Fixed chat-bug (that from a certain moment, nobody could talk) +- Fix: Fixed weight for double-head trains and with that the acceleration (now maglev lvl4 can reach their top speed, and are faster than lvl3) +- Fix: Full-Loading trains no longer get 'lost' after a while +- Fix: Graphs were not updated correctly when one graph with a certain selection was already open and another graph window was opened +- Fix: In multiplayer clientlist can only be opened once +- Fix: Loan does not count against the company value +- Fix: Nasty bug where one could build one station OVER the other +- Fix: No crash when creating a game with New English town names any more +- Fix: Now helicopters will use a hangar in schedule to be replaced in, even if they are only set to service there. Since helicopters are serviced at helipads, they will only go there if they needs to be replaced or renewed. They will also use a hangar in an airport in the schedule if needed +- Fix: Only a server can rename a town in a MP game +- Fix: Really old maps do load again +- Fix: Refit engine button is now disabled when cargo capacity equals zero +- Fix: Server issue where some company names were wrong +- Fix: Ship Vehicle Lists are now redrawn correctly +- Fix: Signal stays red if a track is removed +- Fix: Solve AI related order-problem +- Fix: Starting openttd with -g now acts normal +- Fix: The cost for an autorenew was not always send to the right player ;) +- Fix: Autorenewing multiheaded train engines now costs the correct amount. Used to be twice the correct price +- Fix: The scrollbar in the network gui (server list) now updates when scrolling +- Fix: Train crashes should no longer desync the game +- Fix: When deleting an order, the next pointer was not cleared, resulting in some unusual behaviour from time to time +- Fix: You can now also delete automatically found servers by pressing 'del' +- Fix: You should no longer be able to delete bridges on any type of underground when there is a vehicle on it + + +0.3.5 (2004-12-24) +------------------------------------------------------------------------ +- Feature: [Network] New network, very stable, a lot of new features +- Feature: [Network] Ingame Serverlist (with online game-servers to join) +- Feature: [Network] Webbased Serverlist: http://servers.openttd.org/ +- Feature: [Network] Added dedicated server support +- Feature: [Network] Cheat protection in MultiPlayer +- Feature: [Network] Patch settings are also synced with the server +- Feature: [Network] Chat +- Feature: Custom currency settings +- Feature: Per-station vehicle lists +- Feature: More realistically sized catchment areas +- Feature: Sticky windows +- Feature: Even better support for NewGRF-files +- Feature: Implement improved vehicle loading algorithm +- Feature: Even more advanced console +- Feature: Game compiles under BEOS_SERVER +- Feature: Game compiles under OS/2 (no network-support) +- Feature: OpenTTD runs with the grf files of the DOS version +- Feature: [Big Endian computers, which are mac and MorphOS] Load savegames by TTD(Patch) +- Add: 'l' opens the landscaping toolbar globally +- Add: Make the town sometimes build streets on slopes +- Add: Manpage +- Add: New checkpoint graphics +- Add: SHIFT+DEL now deletes all non-vital windows (only status bar and main bar remain) +- Add: Windows now shows revision, release information in title bar +- Add: Windows snap at each other +- Add: Spanish, Catalan and Icelandic +- Change: [OSX] Moved data and lang folders inside OpenTTD. This got rid of the package system too, making installing/updating easier +- Fix: [OSX] Music is now on by default again +- Fix: [OSX] Made error opens the console +- Fix: [SDL] Added a confirmation dialogue when quitting the game +- Fix: A train can leave and enter the same depot at the same time, then the train simply got stuck +- Fix: Crash when making png screenshot with odd resolution +- Fix: Directories in *nix are now sorted alphabetically in ascending order +- Fix: Do not consider a road station as street when growing the town +- Fix: Engines from other climates do not appear any more when never_expire_vehicles is enabled +- Fix: Game options (like drive side) are not taken from the scenario when using 'new game' command +- Fix: Order checker now correctly detects station with invalid facilities +- Fix: Polished GUI in a lot of ways +- Fix: Saving or loading a map doesn't pauses the game anymore +- Fix: Some bridge part is not displayed transparent in transparent mode +- Fix: Starting with -r option allows all resolutions +- Fix: The pathfinder no longer sees rail with another owner as a possible route +- Fix: Unable to select other screenshot format in Game Option +- Fix: Unwanted town renaming +- Fix: Vehicles slow down under bridge if the track is on a foundation +- Fix: You can no longer change name of waypoints whom are owned by somebody else +- Fix: Shares are now also sold when a company goes bankrupt [SF#1090313] +- Fix: It is no longer possible to crash trains of other companies by building a depot close to a station; trains do no longer enter tiles that do not belong to his owner [SF#1087701] +- Fix: Crashed trains are not reported to have too few orders any more [SF#1087403] +- Fix: Backup-order-list was not closed with an OT_NOTHING, [SF#1086375] +- Fix: Docks now have a button to display the catchment area [SF#1085255] +- Fix: Invisible trains. Weird macros and MSVC optimising do not always mix [SF#1070274] +- Fix: Number of passengers and mail in exclusive test offer window is swapped [SF#1068269] +- Fix: Pause key pauses the game [SF#1066504] +- Fix: Resetting file name after deleting a file [SF#1066121] +- Fix: Code error in win32.c Thanks Shai [SF#1066114] +- Fix: Windows can be placed behind toolbar [SF#1065247] +- Fix: Editor Map-Menu wrong String [SF#1064742] +- Fix: Always report a bus/lorry station as impassable [SF#1058809] +- Fix: Refit train window stays open [SF#1053397] +- Fix: Incorrect Tooltip in Road Vehicle List [SF#1050993] +- Fix: Monorail and Maglev sounds are swapped [SF#1048596] +- Fix: Flooded wagons in depots do not keep constantly exploding any more [SF#1040119] +- Fix: Bug about lowering tracks built on slopes [SF#1035303] +- Fix: 'Allow goto depot' turned off, no checkpoints in orders [SF#1035066] +- Fix: Place sign and blue message box [SF#1034318] +- Fix: Wrong mapping between music titles and songs [SF#1033947] +- Fix: Some screen sizes crashes OpenTTD. Fix in general bug that only allows resolutions which were multiple of 8 in width and height. Also use closest possible resolution in fullscreen if window size is not a valid resolution [SF#1030393] +- Fix: 'Service at' orders ignored after 2090. After 2090 year is reset to 1. Jan 2090, so most of the time, last service was in the future and no service ensured [SF#1030275] +- Fix: Building a station acted weird in some rare situations [SF#1029064] +- Fix: Ships could unload cargo at stations without docks [SF#1022227] +- Fix: Wrong trees (toyland's) in sub-tropical landscape style [SF#999669] +- Fix: High bridge rendering error [SF#993500] +- Fix: Disabled buttons flicker no more [SF#991101] +- Fix: Start/stop flag in train depots always works, regardless of the horizontal scroll position [SF#985925] +- Fix: Un-owned rail. Trains could cross competitor's tracks if there was a road-crossing over it [SF#985439] +- Fix: Pathfinding bug; train likes the roundabout. If train needs servicing it will now look 16 tiles along the track instead of 12 tiles Manhattan style [SF#982611] +- Fix: Fullscreen. New button 'Fullscreen' in 'Game Options' menu which lets you set fullscreen ingame [SF#967096] +- Fix: No longer road/rail crossing signals hang when a train is reversed at the wrong moment [SF#958098] +- Fix: Ctrl + d bug. Longest outstanding bug has been fixed [SF#926105] + + +0.3.4 (2004-09-14) +------------------------------------------------------------------------ +- Add: Dutch translation +- Add: Generalised A* Algorithm +- Add: Generalised queues (Fifo, Stack, InsSort, BinaryHeap) +- Change: Changed 'terraforming' to 'landscaping' +- Change: Changed default options (road side, distance units, currency) to most commonly used options +- Change: Disable 'Submit Report' and 'Show Details' on OpenTTD error window on Windows. Currently of no use, since no developers have assembly knowledge +- Change: Removed patch no_train_service. Instead you can set the default service interval for any vehicle type to 'disabled' +- Codechange: Comments added to the code +- Codechange: Made bridge building code more readable [SF#996244] +- Feature: 'None' as option for number of industries in difficulty settings +- Feature: Add many random industries and towns in scenario editor +- Feature: Added Autosignals, just like Autorail. Can copy signal style, convert signal<->semaphore, etc +- Feature: Added level land button to scenario editor +- Feature: Added never_expire_vehicles to patches GUI +- Feature: Added new icons for landscaping toolbar +- Feature: Added original vehicle names file. Select it from the list. Vehicles will have real name, all other strings are in English +- Feature: Added/heavily modified patch by truesatan cheat change date +- Feature: Align toolbar left/centre/right patch +- Feature: All TTDLX kind of savegames are supported (.SS1, .SV1, .SV2, .SV0, .SS0) +- Feature: Alpha version of a new AI +- Feature: Autodetect server in LAN via udp +- Feature: Build_date of station (viewable with Query tool) +- Feature: Cheat switch climate +- Feature: Company HQ can now be moved somewhere else (cost 1% of company value). Water floods HQ +- Feature: Competitors menu under patches +- Feature: Copy/share orders now works from ship depot window for ships and hangar window for aircraft +- Feature: Difficulty settings window has been changed +- Feature: Enable/disable all buttons in message settings +- Feature: Executable is now openttd(.exe) always +- Feature: General protection around Sprites +- Feature: Ingame console +- Feature: Invalid (void) orders in schedule are highlighted in red +- Feature: Invisible trees when in transparent mode (patch entry) +- Feature: Option to sort vehicles in vehicle-list window by different criteria +- Feature: Performance details window in company league menu +- Feature: Proper crediting to graphics artists to about box +- Feature: Removing town roads has been fine tuned +- Feature: Safeguard against invalid values in Patches window. Values will stick to their defined min and max values +- Feature: Sorting savegames, scenarios by name/date +- Feature: Terraforming toolbar (in the plant tree menu) +- Feature: The extra dynamite patch has been changed a bit +- Feature: Warning when a vehicle has invalid orders +- Feature: Water floods everything, including vehicles +- Feature: Working multiplayer gui +- Feature: No extra frequent jet crash on small airports [SF#976127] +- Feature: Scrollto Station in Orders. CTRL click on orders of a vehicle and main-window scrolls to that station [SF#992998] +- Feature: Improved industry directory [SF#997115] +- Feature: Euro introduction news item [SF#1003350] +- Feature: Percent-based service intervals. Send a vehicle to depot after it has lost X% of its reliability [SF#1009708] +- Feature: Extra Viewport [SF#1009710] +- Feature: Show max loan in finances window [SF#1024044] +- Fix: (Unix) loading old scenarios (.sv0) works again +- Fix: 64bit CPU fixes +- Fix: 64x64 stations are now nicely painted +- Fix: A lot of network fixing +- Fix: A lot of old AI fixed +- Fix: All scenarios, savegames show up with their correct name +- Fix: Automatic oil refinery generation in editor +- Fix: Autosave folder was not created on MorphOS +- Fix: Bridge slope fix again +- Fix: Bulldozing stuff with cheat magic_dynamite turned on does not lower city ratings +- Fix: Change SDL_HWSURFACE back to SDL_SWSURFACE (Diablo-3D); better performance +- Fix: Coast line near edge of map and near oilrigs +- Fix: Company-value was not updated immediately if legend was changed +- Fix: Delete canal under bridge was not possible +- Fix: Disable Fast Forward in network games visually (did not work anyways, just showed graphical output) +- Fix: Error message for 'game load failed' when no town is in a scenario +- Fix: Game not pausing when saveload dialogue is clicked in main menu +- Fix: Load Scenario fix +- Fix: Make Endianness check 100% accurate +- Fix: Memory leak in news system +- Fix: Monorail/maglev became available around 1927 +- Fix: Move around sort-widgets a bit so it looks more natural +- Fix: Music now finally works on WinXP. DirectMusic is now default for an OS >= WinNT4 (WinNT4, Win2k, WinXP), and MIDI driver for lower OS's (Win95, Win98, WinME, etc) +- Fix: Old scenarios have correct colour +- Fix: Placing/editing signs signs is possible in paused mode +- Fix: Player window fixes, Getstring id0 fixes, Finances window is now ok +- Fix: Playing new game with scenarios in windows works +- Fix: Possible to disable some patches (e.g. default service interval) again by setting them to 0 +- Fix: Problems around exclusive transport rights +- Fix: Rail road crossings on slopes are now possible +- Fix: Random crash when player-face was displayed in error-dialogue +- Fix: Rare mousewheel scrolling with scrollbar crash +- Fix: Road vehicles do not get stuck any more at stations +- Fix: Savegames are sorted with newest date first by default +- Fix: Scenario editor now asks before it generates a random landscape +- Fix: Slopes graphics fix +- Fix: Small gap between station button and signal button in rail toolbar +- Fix: Some minor fixes around GetTileTrackStatus +- Fix: Sorter icon pointing down 'v' sorts in every window lowest value first, '^' highest value first +- Fix: Starting a new game in DesertLandscape crashed the game +- Fix: Stupid bug in company league window if non-player is first +- Fix: Two non-AI players when loading a scenario +- Fix: Unix uses same sorting of directories, files as windows +- Fix: When adding parts to a station max size is not 15x15 anymore, but _patches.station_spread +- Fix: Win98 crashes related to music/sound +- Fix: Wrong building of road-slopes for a future AI/Town +- Fix: Wrong pathfinding when northern station tile is missing +- Fix: You cannot take ownership of an oilrig by building right next to it +- Fix: [Makefile] Fixed issue where sdl-config was needed even on systems without SDL +- Fix: [SDL] Performance fix fo palette animation and mouse jumping +- Fix: [SDL] Same resolution was displayed more than once in game options +- Fix: [SDL] Smoother mouse and performance fix, like in the Windows video driver +- Fix: Wrong trains you can buy with scenarios [SF#963056] +- Fix: Minimap crash [SF#972087] +- Fix: Bug in 'weird non-uniform stations handling' [SF#972247] +- Fix: Parent_list was too small [SF#976583] +- Fix: Memory leak in parent_list [SF#981934] +- Fix: Max_loan in editor bug [SF#982666] +- Fix: Bridge building over boats [SF#987888] +- Fix: Cargo delivery area patch for bug [SF#990770, SF#989322] +- Fix: No tunnel crash [SF#992726] +- Fix: Light House Placement Bug [SF#993339] +- Fix: Pressing alt locks the game - sort of a bug [SF#993374] +- Fix: Buildings on water [SF#993493] +- Fix: No canal building under bridge [SF#993512] +- Fix: UDP Fixes [SF#993829] +- Fix: Train drivers dies two times [SF#994067] +- Fix: Road depot - bus/lorry station [SF#994720] +- Fix: _local_player fixes. Fixes wrong memory access [SF#996025] +- Fix: Bridge Bug fixed bug fixed again [SF#996065] +- Fix: Weird two tile bridges on slopes [SF#996065] +- Fix: Empty strings in signs [SF#997303] +- Fix: Junction after tunnel bug [SF#997703] +- Fix: 'autosave' directory creation (MorphOS/AmigaOS) [SF#999592] +- Fix: I lost all wagons. Half-assed fix for lost wagons. But now users can at least fix this problem. Consolecommand 'resetengines' [SF#1001540] +- Fix: BuildRoadOutsideStation fix [SF#1006530] +- Fix: Autorenew issues [SF#1006715] +- Fix: Copy orders between bus/truck possible [SF#1007272] +- Fix: Scenario editor pause bug [SF#1007630] +- Fix: Signals not updated after ClearTunnel Bug [SF#1008605, SF#985920] +- Fix: Too many save games prevented loading [SF#1009385] +- Fix: Problem with transferred cargo crashes game [SF#1009567] +- Fix: Build in pause is now a cheat instead of a patch [SF#1009621] +- Fix: Wrong multihead selling [SF#1009631] +- Fix: Turning on the magic bulldozer removes oil rigs [SF#1010833] +- Fix: Drunk pilot [SF#1012086] +- Fix: TileAddWrap() gave wrong results [SF#1014278] +- Fix: Cached_sprites does now work again [SF#1016954] +- Fix: Bug when dragging a part of a multiheaded engine to 'sell-whole-train' [SF#1022689] +- Fix: Fix for MouseWheel assert error in non-zoomable viewports. Zooming now will only occur if mousepointer is either in an extra viewport window, or main game-window [SF#1023971] +- Fix: Company value problem (again). Now company value rightly shows the value, including ALL your money [SF#1025836] +- Fix: Company values bigger than int32 were put to negative [SF#1025836] +- Fix: Long bridges had negative value [SF#1025836] +- Fix: Vehicle depots not transparent with transparent buildings [SF#1026271] + + +0.3.3 (2004-07-13) +------------------------------------------------------------------------ +- Feature: MorphOS/AmigaOS network support +- Feature: Improved German town name generator +- Feature: Transparent station signs +- Feature: Show total cargo per wagon type in train details window +- Feature: Bridges on slopes +- Feature: Added Galician translation +- Feature: Extra dynamite, allow the removal of town-owned roads, bridges, tunnels for a popularity rating penalty +- Feature: Magic bulldozer cheat, that lets you remove industries, unmovables and town-owned buildings, roads and bridges +- Feature: Enabled 'remove' button for stations +- Feature: Cheat GUI (activate with ctrl-alt-c) The game remembers if you have used a cheat +- Feature: Station sort implemented using qsort() +- Feature: Station list shows #of stations owned by player +- Feature: Split canal/lock tool in two tools, one for building canals, one for locks +- Feature: Make the HQ generate passengers and mail +- Feature: Display number of houses in town overview window +- Feature: Land info now shows type of signal +- Feature: Realistic train reversing +- Feature: Added support for 64 bit CPUs +- Feature: Added water quantity level 'very low', which is the default for easy mode now +- Feature: Realistic acceleration turned on, train must first slow down and stop before it can reverse +- Feature: [MorphOS] Various small improvement to make the the game feel more native +- Feature: Alt + f now toggles full screen (alt + enter still works) +- Feature: [OSX] Command + q shows the quit window and command + f or enter toggles full screen (alt and control still works too) +- Feature: Autorenew, autorenews vehicles if enabled +- Feature: (Incomplete) news history window +- Feature: Larger smallmap size +- Feature: Austrian Citynames +- Feature: Repaying most possible debt +- Feature: Added Polish translation +- Feature: Added Danish translation +- Feature: Initial GRF support.You have to enable it in openttd.cfg using [NewGRF] setting +- Feature: Smooth economy changes +- Feature: TTDPatch-style gotodepot. Ship depots and aircraft hangars can be inserted in the schedule as well +- Feature: Ability to add 'service if needed' orders (the 'full load' button changes to 'service' after selecting a depot order) +- Feature: If a vehicle has depot orders in its schedule, automatic servicing is disabled +- Feature: Patch setting so that helicopters get serviced automatically on helipad +- Feature: Centre toolbar on screen +- Feature: Sort savelist by date +- Feature: Allow scrolling in both directions +- Feature: Two new airports (metropolitan in 1980 and international in 1990) +- Feature: Resizing the window in all SDL builds +- Feature: Added MIDI flag to makefile to set custom path to midi player +- Change: Autosaves are now placed in save/autosave +- Change: Default savegame directory is /save in Linux +- Change: Screenshots are saved to PERSONAL_DIR (unix) +- Change: Scenarios now have the file extension .scn +- Change: Default network port from 12345 (known trojan) to 3979 +- Change: Crossing tunnels is now considered a cheat +- Change: Made helicopters able to land on small airports again +- Fix: Removing and upgrading tracks under a bridge when a train is on the bridge +- Fix: Pause button was not synced in network games +- Fix: Crash caused by invalid screen resolutions +- Fix: AI can not build tubular bridges in 1950, etc. Same restrictions apply to it, as to human players +- Fix: Volume, litres, was x100, should be x1000 +- Fix: Bridge building by towns was screwed when executed without testing first +- Fix: Better AI route finding +- Fix: AI builds less inner-city bus stations +- Fix: Better industry spreading on random maps +- Fix: Two industries that accept the same goods can never be very close to each other +- Fix: Destroying bridge (over water or 'higher bridge' with vehicle on it) +- Fix: Game crashes when you hit the build rail button +- Fix: Some scenarios had a max_railtype of 0 +- Fix: Bribe Authority. A failed attempt to bribe is now also stored in savegame +- Fix: 80% CPU load paused in fast-forward +- Fix: Some airport runways were treated +- Fix: Minor minimap glitch +- Fix: Station sorting scroll fails with not enough stations +- Fix: Desert ground for depots in the desert +- Fix: Trains could run on wrong track type under bridges +- Fix: Screenshot hangs +- Fix: Wrong sound with ships +- Fix: Toy shop closes even though it has supply +- Fix: Nordic characters +- Fix: Also restore Service Interval when rebuying vehicle +- Fix: Crash with map bits > 8 +- Fix: UFO crash in bus stop +- Fix: Town actions has empty row +- Fix: Train stuck with the head in one depot and tail in another +- Fix: Optimised random radio tower spreading +- Fix: Ground below trees is sometimes not covered by snow +- Fix: Fast forward button in scenario editor +- Fix: Screenshot hotkey does not function in scenario editor +- Fix: Allow deleting a bridge if a vehicle is below +- Fix: Crash loading a scenario +- Fix: Build tracks on water +- Fix: Fast forward button pressed with tab +- Fix: Vehicles do not get old +- Fix: Finance bug with some original scenarios +- Fix: 'Stopped' is shown when train is stopping and 'Reverse' is clicked +- Fix: 100% CPU bug +- Fix: Crash when AI builds airport +- Fix: Plays wrong music on main screen +- Fix: Inflation was way too high when interest rate = 0 +- Fix: Cannot sell anything if money is TOO negative +- Fix: Fast forward button resets +- Fix: 'Refit train' button remains +- Fix: Enable up/down scrolling with the mouse +- Fix: 1920 all trains +- Fix: Wrong heli breakdown speed +- Fix: Station list cargo waiting display bug +- Fix: Bug that could allow rails on steep slopes +- Fix: Train depots and checkpoints not flooded by water +- Fix: Added command line option (-i) to deactivate the grf check +- Fix: Signal bug [SF#949929] + + +0.3.2.1 (2004-05-23) +------------------------------------------------------------------------ +- Feature: Now builds on FreeBSD +- Feature: Now builds on MorphOS +- Fix: Use english.lng by default +- Fix: No bridges available in 1920 +- Fix: Czech file was missing + + +0.3.2 (2004-05-22) +------------------------------------------------------------------------ +- Feature: HP for trains limited to 16bit int +- Feature: Added Czech translation +- Feature: Train refitting +- Feature: Auto euro +- Feature: Industry directory +- Feature: Added extend vehicle life/noexpire patch +- Feature: Show revision number in title bar +- Feature: Random network games +- Feature: Smallmap remembers size +- Feature: Remember value of show town names in smallmap +- Feature: Norwegian translation +- Feature: Norwegian currency +- Feature: Slovak language +- Feature: Use SO_REUSEADDR on listen socket +- Feature: Unix sigabort handling +- Feature: Hungarian translation +- Feature: Added Norwegian translation +- Feature: Added more default resolutions +- Feature: Return error message if DOS grf files are used +- Feature: Bemidi support +- Feature: Added Icelandic currency +- Change: Plant area of trees now allowed for 20x20 area +- Change: 'kmh^-1' to 'km/h' +- Change: Show original savegame names for oldstyle savegames +- Change: Autosave go to autosave/ +- Fix: Do not allow building rail stations on airports or bus stations +- Fix: Canal tool resets after 1 use +- Fix: Enable mouse wheel scrolling and zooming in SDL +- Fix: Construct industries producing raw materials +- Fix: Loading TTD saves gave incorrect reliability parameters for wagons +- Fix: Fixed order restore bug in network play +- Fix: Network sync fix for train goto depot +- Fix: Only one statue per player per town +- Fix: Enhanced patch configurator +- Fix: If realistic acceleration was enabled, train did not accelerate if they entered a tunnel right after a slope +- Fix: Remove SDL frameskip message +- Fix: Road vehicle on hills speedfix +- Fix: CompanyValueGraph window too small for currency +- Fix: Mkdir() problem in unix.c +- Fix: Client kills server if it leaves a networkgame +- Fix: Smoother mouse cursor +- Fix: Fixed a couple of overlapping memcpys +- Fix: Quit to beos +- Fix: Dragging to build canals sometimes crashed +- Fix: Cactus plants died on desert +- Fix: Invalid letters in Spanish town names +- Fix: Rail upgrade button +- Fix: Makefile reorganisation +- Fix: Zoom out button not greyed out +- Fix: No space between some values and units +- Fix: Station catchment outline-tiles were not shown properly on slopes +- Fix: Oil rig station was not properly deleted +- Fix: Fixed making screenshots in scenario editor +- Fix: Mac patches +- Fix: Fixed alignment issue in station drawing + + +0.3.1 (2004-04-26) +------------------------------------------------------------------------ +- Feature: Bridge pillars for higher bridges +- Feature: Remember cargo payment rates selection, default to all +- Feature: Fast forward button +- Feature: Copy/share orders from trains in depot +- Feature: Swedish translation +- Feature: Dragging to construct canals +- Feature: Can now have more than 128 towns +- Feature: Always allow building small airports patch +- Feature: Colourful newspaper after a certain date +- Feature: Build while paused patch +- Feature: Polish town names +- Feature: Clear area now works in scenario editor +- Feature: Drag&drop stations +- Feature: More realistic train starting and stopping +- Change: New directory structure (*.grf+sample.cat in data subdir, *.lng in lang subdir) +- Fix: Shift+arrows keys scrolls faster +- Fix: 'Monorail in 1985' which allowed you to build monorail/maglev at any year [SF#941880] +- Fix: Town ratings when companies are deleted/merged +- Fix: Vehicle reliability calculation in third phase +- Fix: Random world button in scenario editor does not build cities, industries, trees +- Fix: Loading worlds with no towns now fails +- Fix: Outdated sort order after station renaming +- Fix: Better train detection for copy orders +- Fix: Euro currency bug [SF#938481] +- Fix: Go to xxx road depot selection bug (2) [SF#938170] +- Fix: Scrolling and newspaper in title screen [SF#934520] +- Fix: Incorrect cargo_days for trains +- Fix: Array bounds error with train breakdown speeds +- Fix: Towns deleting random tiles around houses +- Fix: Incorrect road vehicle list caption for competitors +- Fix: Vehicle menu greying after a bankruptcy +- Fix: Selective road removal +- Fix: Make houses available in 1920 to prevent hang +- Fix: Duration of breakdown smoke +- Fix: Slope bug under bridges +- Fix: Do not play invalid sounds (fixes road reconstruction crash) +- Fix: Display correct train power with multihead engines +- Fix: Buffer overflow caused by too long string in english.lng +- Fix: Destroying things with no money + + +0.3.0 (2004-04-14) +------------------------------------------------------------------------ +- Feature: Cost estimation with Shift +- Feature: Added patch for starting_date, takes a value on the form yyyy, yyyymm or yyyymmdd +- Feature: Support for multiheaded trains +- Feature: Sell whole train by dragging loco to special trashcan +- Feature: Drag the whole train with ctrl in depot +- Feature: Added convert rail tool +- Feature: Patch to select what vehicle types the ai will build +- Feature: Better slope graphics +- Feature: New pathfinding algorithm for trains (enable with new_pathfinding) +- Feature: Added patch to use timidity for BeOS +- Feature: Mousewheel can now be used to scroll in windows +- Feature: Added coordinate display to landinfo window +- Feature: Change default servicing interval for vehicles +- Feature: Change max # of vehicles per player +- Feature: Nonuniform stations patch +- Feature: Moved error message box out of the way +- Feature: Canals/shiplifts +- Feature: Build tree of random type +- Feature: Build trees on area +- Feature: Added colour coded vehicle profits +- Feature: Ability to close error messages with space +- Feature: Network games (currently unsupported) +- Feature: Bigger demolish tool +- Feature: Two more bridges +- Feature: Improved depot finding +- Feature: Bribe the town authority +- Feature: Allow building many trees on a single tile +- Feature: Added snow_line_height setting, only affects new games +- Feature: Errmsg_duration controls how long error messages are displayed +- Feature: Fullscreen_bpp setting in [win32] sets the bpp to use in fullscreen mode +- Feature: Euro symbol +- Feature: High bridges +- Feature: ZLIB savegames (smaller than before) +- Feature: PNG, PCX screenshot support +- Feature: Indicate with grey in vehicle popup menus if company has no vehicles of that type +- Feature: Clicking on the money brings up finances +- Feature: [OSX] Distribution now uses Apples package system for easier updates +- Feature: [OSX] Application is now a proper bundle application +- Change: [Windows] Use save/ as save folder +- Change: Moved date in news window +- Change: Do not check if tiles around the clicked station is a station in order gui +- Change: Keep checkpoint button down after placing +- Change: [Windows] Moved disk devices to bottom of list +- Change: Changed speedkey from Shift to Tab +- Change: Enhanced patches window with pages +- Change: Do not slow down trains as much on hills +- Change: Limit amount of radiotowers +- Change: Changed intro graphics +- Change: All player stuff is deleted when you load a scenario +- Fix: Aircraft terminal was not properly freed if aircraft crashed +- Fix: Fixed station acceptance bug +- Fix: Fixed buy shares in company +- Fix: Only deliver goods to stations that have a rating != 0 +- Fix: Added F hotkeys in scenario editor +- Fix: Unable to raise land next to signal +- Fix: Aircraft was shown instead of ships in player overview window +- Fix: Updated installer to take care of savegames more carefully +- Fix: Do not make a new subsidy if there already exists one that is currently active by a company +- Fix: Town directory sometimes showed huge numbers +- Fix: Fixed bugs when changing owners of items (pieces of rail were not always deleted), +- Fix: Fixed bug with large stations in train pathfinder +- Fix: Deleting docks does not produce land +- Fix: Deleting ship depot does not produce land +- Fix: Buoy is now treated as water when flooding +- Fix: Combo presignals bug fix +- Fix: Prevent going to 0,0 if airport/docks is deleted +- Fix: French town names had bad letters in them +- Fix: Order list when replacing train did not work properly +- Fix: Start in the middle of the map +- Fix: More error tolerant saveload code +- Fix: [OSX] Now runs even if SDL is not present on the system +- Fix: [OSX] Now runs on systems older than 10.3 +- Fix: [OSX] Altered compiler settings to make a completely stable app + + +0.2.1 (2004-04-04) +------------------------------------------------------------------------ +- Feature: 'A' hotkey now always opens autorail +- Feature: X can be used to toggle transparent buildings +- Feature: Hotkeys 1-9 can be used to build a bridge in the bridge window +- Feature: Added more hotkeys in the road build window +- Change: Moved autorail button +- Fix: Copy orders crashed if you clicked on a wagon +- Fix: Do not show transparent buildings in intro +- Fix: Installer does not delete savegames + + +0.2 (2004-04-03) +------------------------------------------------------------------------ +- Feature: Autoscroll (only works to left/right) +- Feature: Train checkpoints, instead of TTDPatch's nonstop handling +- Feature: TTDPatch compatible nonstop handling +- Feature: Refresh rate configuration setting +- Feature: Town directory sorting options +- Feature: Pre-signals (ctrl-click on existing signals to change signal type) +- Feature: Show semaphores on the right side if right-sided traffic +- Feature: Patch options configuration window +- Feature: Autorail build tool +- Feature: 'Show yearly finances window' option +- Feature: 'Signals on drive side' patch +- Feature: 'Show full date in statusbar' option +- Feature: Italian translation +- Feature: Road and rail removal by dragging a selection +- Feature: News item for 'train is unprofitable' +- Feature: News item for 'train is lost' +- Feature: [Windows] Double size mode (Ctrl-d to toggle) +- Feature: 'Multiple similar industries in close proximity' option +- Feature: 'Multiple industries per down' option +- Feature: 'Crossing tunnels' option +- Feature: Order sharing and copying ('goto' on other vehicle to copy, ctrl+'goto' to share) +- Feature: Remember last built rail type +- Feature: 'Debtmax' faster loan management with ctrl key +- Feature: 'Go to depot' orders option +- Feature: 'Long bridges' option +- Feature: 'Select goods' option +- Feature: 'No train service' option +- Feature: 'No inflation' option +- Feature: Automatically detect available resolutions +- Feature: 'Full load any' option, as in TTDPatch +- Feature: Automatic detection of available language files +- Feature: German translation +- Feature: Finnish town names +- Feature: Remember custom difficulty settings +- Feature: Configuration file system +- Feature: Show vehicle speed in vehicle view windows +- Feature: Train depot window now has horizontal scrollbar +- Feature: Mammoth trains +- Feature: On-the-fly language selection +- Feature: Load old premade ttd maps (must be renamed to .sv1 extension) +- Change: Increased number of windows on screen to 20 +- Change: [OSX] Start when doubleclicked +- Change: [OSX] Significant performance increase +- Change: Optimised startup time +- Change: Sorted savegame list +- Fix: News window was moved strangely when resizing +- Fix: Fixed sign drawing bug in max zoom out mode +- Fix: Road vehicles sometimes getting stuck +- Fix: Connecting tracks behind depot causing incorrect signal behaviour +- Fix: Save/load diskspace bug +- Fix: Incorrect bridge cost for long bridges +- Fix: Disallow buoy in north corner +- Fix: Shift key now increases game speed only when game window is active +- Fix: Ctrl button now works with SDL driver +- Fix: Incorrect weight displayed in 'new trains' window +- Fix: Incorrect train running cost in newspaper + + +0.1.4 (2004-03-25) +------------------------------------------------------------------------ +- Feature: Crash submit system on Windows +- Feature: Autosave +- Feature: In-game resolution selection via settings window +- Feature: Dutch town names +- Feature: Added load game menu item +- Feature: Build on coasts +- Feature: Allow building transmitters, lighthouses and company headquarters on slopes +- Feature: Now builds on MacOSX +- Change: New savegame format +- Change: New format for english.lng +- Fix: Train smoke clouds +- Fix: Train engine sounds +- Fix: Play all sounds at 11025 hz (fixes certain sounds) +- Fix: Scenario editor desert button now makes desert instead of lighthouse +- Fix: Creating random town in scenario editor crash +- Fix: Candy bubbles sometimes caused crash +- Fix: Wrong speed was shown in news window for some vehicles +- Fix: Graph colour bleeding +- Fix: Arrow keys with SDL driver +- Fix: Do not allow trains to road depots +- Fix: Road vehicle was sometimes shown inside depot +- Fix: Arrow keys in sdl driver were wrong +- Fix: Endianness bugs in save/load +- Fix: Now builds on FreeBSD +- Fix: Screenshot feature now works +- Fix: Rail foundations sometimes displayed unnecessarily +- Fix: Minor AI bugs +- Fix: Fixed industry sounds +- Fix: Bug where ship depots were very expensive +- Fix: BeOS build +- Fix: Yearly expenses data being the same for the past two game years +- Fix: Adding songs to playlists other than custom1 and custom2 +- Fix: First and last tracks playing the wrong music +- Fix: Palette animation for SDL video +- Fix: Get remaining disk space on most Unix-en +- Fix: Screen went black when resizing + + +0.1.3 (2004-03-18) +------------------------------------------------------------------------ +- Feature: Swedish town names +- Feature: More currencies +- Feature: Better window resizing/zooming +- Feature: Added goto road vehicle depot for road vehicle orders +- Feature: Possibility to use either semaphores or signals (Ctrl key) +- Feature: Limited the scrolling rate for year selector in scenario editor +- Feature: Improved mouse scroll zooming +- Feature: Larger stations and possibility to join stations +- Fix: Message options window +- Fix: Company takeover/purchase +- Fix: Station code so it is not possible to steal another player's temporarily deleted station +- Fix: Subsidy owner bug when deleting station +- Fix: Crash when deleting a bridge with a train on it +- Fix: Missing candy initial cargo payment values +- Fix: Goods and Food/FizzyDrinks subsidies +- Fix: Graphical glitch in subsidies window +- Fix: Take over company dialogue was not shown properly +- Fix: Crash if player windows were open while the company went bankrupt +- Fix: Train slowness on hills + + +0.1.2 (2004-03-15) +------------------------------------------------------------------------ +- Feature: Mouse wheel can be used to zoom in out on Windows +- Feature: Implemented some support for resizing the window dynamically in Windows +- Fix: Tunnel mouse icon for maglev and monorail + + +0.1.1 (2004-03-14) +------------------------------------------------------------------------ +- Feature: Preliminary presignal support +- Feature: Centre windows properly in higher resolutions +- Feature: Command line -g flag now optionally takes a game to load +- Add: External MIDI driver for Unix version +- Add: DirectMusic driver for Windows version +- Add: 'build tracks on slopes' feature +- Fix: Problem where directories were not displayed under Linux +- Fix: Colours in map window for routes +- Fix: Road drive side +- Fix: 'Fund road construction' not clickable when unavailable diff --git a/config.cache b/config.cache new file mode 100644 index 0000000..e62ee09 --- /dev/null +++ b/config.cache @@ -0,0 +1 @@ +./configure --ignore-extra-parameters --build="" --host="" --cc-build="gcc" --cc-host="gcc" --cxx-build="g++" --cxx-host="g++" --windres="" --strip="strip" --lipo="" --awk="awk" --os="UNIX" --endian="AUTO" --cpu-type="64" --config-log="config.log" --prefix-dir="/usr/local" --binary-dir="games" --data-dir="share/games/openttd" --doc-dir="share/doc/openttd" --icon-dir="share/pixmaps" --icon-theme-dir="share/icons/hicolor" --man-dir="share/man/man6" --menu-dir="share/applications" --personal-dir=".openttd" --shared-dir="" --install-dir="/" --menu-group="Game;" --menu-name="OpenTTD" --binary-name="openttd" --enable-debug="0" --enable-desync-debug="0" --enable-profiling="0" --enable-lto="0" --enable-dedicated="1" --enable-network="1" --enable-static="0" --enable-translator="0" --enable-unicode="0" --enable-console="1" --enable-assert="0" --enable-strip="1" --enable-universal="0" --enable-osx-g5="0" --enable-cocoa-quartz="1" --enable-cocoa-quickdraw="1" --with-osx-sysroot="0" --with-application-bundle="0" --with-allegro="1" --with-sdl="1" --with-cocoa="0" --with-zlib="1" --with-lzma="1" --with-lzo2="1" --with-xdg-basedir="1" --with-png="1" --enable-builtin-depend="1" --with-makedepend="0" --with-direct-music="0" --with-sort="1" --with-iconv="0" --with-midi="" --with-midi-arg="" --with-libtimidity="0" --with-freetype="1" --with-fontconfig="1" --with-icu="1" --static-icu="0" --with-psp-config="1" --with-threads="1" --with-distcc="0" --with-ccache="0" --with-grfcodec="1" --with-nforenum="1" --with-sse="1" --CC="" --CXX="" --CFLAGS="" --CXXFLAGS="" --LDFLAGS="" --CFLAGS-BUILD="" --CXXFLAGS-BUILD="" --LDFLAGS-BUILD="" diff --git a/config.cache.pwd b/config.cache.pwd new file mode 100644 index 0000000..1cf9e42 --- /dev/null +++ b/config.cache.pwd @@ -0,0 +1 @@ +/home/openttd/openttd-virj-source diff --git a/config.cache.source.list b/config.cache.source.list new file mode 100644 index 0000000..cdadecd --- /dev/null +++ b/config.cache.source.list @@ -0,0 +1,1204 @@ +# Source Files +airport.cpp +animated_tile.cpp +articulated_vehicles.cpp +autoreplace.cpp +bmp.cpp +cargoaction.cpp +cargomonitor.cpp +cargopacket.cpp +cargotype.cpp +cheat.cpp +command.cpp +console.cpp +console_cmds.cpp +cpu.cpp +crashlog.cpp +currency.cpp +date.cpp +debug.cpp +dedicated.cpp +departures.cpp +depot.cpp +disaster_vehicle.cpp +driver.cpp +economy.cpp +effectvehicle.cpp +elrail.cpp +engine.cpp +fileio.cpp +fios.cpp +fontcache.cpp +fontdetection.cpp +base_consist.cpp +gamelog.cpp +genworld.cpp +gfx.cpp +gfxinit.cpp +gfx_layout.cpp +goal.cpp +ground_vehicle.cpp +heightmap.cpp +highscore.cpp +hotkeys.cpp +infrastructure.cpp +ini.cpp +ini_load.cpp +landscape.cpp +linkgraph/demands.cpp +linkgraph/flowmapper.cpp +linkgraph/linkgraph.cpp +linkgraph/linkgraphjob.cpp +linkgraph/linkgraphschedule.cpp +linkgraph/mcf.cpp +linkgraph/refresh.cpp +map.cpp +misc.cpp +mixer.cpp +music.cpp +network/network.cpp +network/network_admin.cpp +network/network_client.cpp +network/network_command.cpp +network/network_content.cpp +network/network_gamelist.cpp +network/network_server.cpp +network/network_udp.cpp +openttd.cpp +order_backup.cpp +pbs.cpp +progress.cpp +rail.cpp +rev.cpp +road.cpp +roadstop.cpp +screenshot.cpp +#if SDL + sdl.cpp +#end +settings.cpp +signal.cpp +signs.cpp +sound.cpp +sprite.cpp +spritecache.cpp +station.cpp +strgen/strgen_base.cpp +string.cpp +stringfilter.cpp +strings.cpp +story.cpp +subsidy.cpp +textbuf.cpp +texteff.cpp +tgp.cpp +tile_map.cpp +tilearea.cpp +townname.cpp +#if WIN32 +#else + #if WINCE + #else + #if OS2 + os/os2/os2.cpp + 3rdparty/os2/getaddrinfo.c + 3rdparty/os2/getaddrinfo.h + 3rdparty/os2/getnameinfo.c + 3rdparty/os2/getnameinfo.h + #else + #if OSX + os/macosx/crashlog_osx.cpp + #else + os/unix/crashlog_unix.cpp + #end + os/unix/unix.cpp + #end + #end +#end +vehicle.cpp +vehiclelist.cpp +viewport.cpp +#if SSE +viewport_sprite_sorter_sse4.cpp +#end +waypoint.cpp +widget.cpp +window.cpp + +# Header Files +#if ALLEGRO + music/allegro_m.h + sound/allegro_s.h + video/allegro_v.h +#end +aircraft.h +airport.h +animated_tile_func.h +articulated_vehicles.h +autoreplace_base.h +autoreplace_func.h +autoreplace_gui.h +autoreplace_type.h +autoslope.h +base_media_base.h +base_media_func.h +base_station_base.h +bmp.h +bridge.h +cargo_type.h +cargoaction.h +cargomonitor.h +cargopacket.h +cargotype.h +cheat_func.h +cheat_type.h +clear_func.h +cmd_helper.h +command_func.h +command_type.h +company_base.h +company_func.h +company_gui.h +company_manager_face.h +company_type.h +console_func.h +console_gui.h +console_internal.h +console_type.h +cpu.h +crashlog.h +currency.h +date_func.h +date_gui.h +date_type.h +debug.h +video/dedicated_v.h +departures_func.h +departures_gui.h +departures_type.h +depot_base.h +depot_func.h +depot_map.h +depot_type.h +direction_func.h +direction_type.h +disaster_vehicle.h +music/dmusic.h +driver.h +economy_base.h +economy_func.h +economy_type.h +effectvehicle_base.h +effectvehicle_func.h +elrail_func.h +engine_base.h +engine_func.h +engine_gui.h +engine_type.h +error.h +fileio_func.h +fileio_type.h +fios.h +fontcache.h +fontdetection.h +base_consist.h +gamelog.h +gamelog_internal.h +genworld.h +gfx_func.h +gfx_layout.h +gfx_type.h +gfxinit.h +goal_base.h +goal_type.h +graph_gui.h +ground_vehicle.hpp +group.h +group_gui.h +group_type.h +gui.h +heightmap.h +highscore.h +hotkeys.h +house.h +house_type.h +industry.h +industry_type.h +industrytype.h +infrastructure_func.h +ini_type.h +landscape.h +landscape_type.h +language.h +linkgraph/demands.h +linkgraph/flowmapper.h +linkgraph/init.h +linkgraph/linkgraph.h +linkgraph/linkgraph_base.h +linkgraph/linkgraph_gui.h +linkgraph/linkgraph_type.h +linkgraph/linkgraphjob.h +linkgraph/linkgraphjob_base.h +linkgraph/linkgraphschedule.h +linkgraph/mcf.h +linkgraph/refresh.h +livery.h +map_func.h +map_type.h +mixer.h +network/network.h +network/network_admin.h +network/network_base.h +network/network_client.h +network/network_content.h +network/network_content_gui.h +network/network_func.h +network/network_gamelist.h +network/network_gui.h +network/network_internal.h +network/network_server.h +network/network_type.h +network/network_udp.h +newgrf.h +newgrf_airport.h +newgrf_airporttiles.h +newgrf_animation_base.h +newgrf_animation_type.h +newgrf_callbacks.h +newgrf_canal.h +newgrf_cargo.h +newgrf_class.h +newgrf_class_func.h +newgrf_commons.h +newgrf_config.h +newgrf_debug.h +newgrf_engine.h +newgrf_generic.h +newgrf_house.h +newgrf_industries.h +newgrf_industrytiles.h +newgrf_object.h +newgrf_properties.h +newgrf_railtype.h +newgrf_sound.h +newgrf_spritegroup.h +newgrf_station.h +newgrf_storage.h +newgrf_text.h +newgrf_town.h +newgrf_townname.h +news_func.h +news_gui.h +news_type.h +music/null_m.h +sound/null_s.h +video/null_v.h +object.h +object_base.h +object_type.h +openttd.h +order_backup.h +order_base.h +order_func.h +order_type.h +pbs.h +progress.h +querystring_gui.h +rail.h +rail_gui.h +rail_type.h +rev.h +road_cmd.h +road_func.h +road_gui.h +road_internal.h +road_type.h +roadstop_base.h +roadveh.h +safeguards.h +screenshot.h +sdl.h +sound/sdl_s.h +video/sdl_v.h +settings_func.h +settings_gui.h +settings_internal.h +settings_type.h +ship.h +signal_func.h +signal_type.h +signs_base.h +signs_func.h +signs_type.h +slope_func.h +slope_type.h +smallmap_gui.h +sortlist_type.h +sound_func.h +sound_type.h +sprite.h +spritecache.h +station_base.h +station_func.h +station_gui.h +station_type.h +statusbar_gui.h +stdafx.h +story_base.h +story_type.h +strgen/strgen.h +string_base.h +string_func.h +string_type.h +stringfilter_type.h +strings_func.h +strings_type.h +subsidy_base.h +subsidy_func.h +subsidy_type.h +tar_type.h +terraform_gui.h +textbuf_gui.h +textbuf_type.h +texteff.hpp +textfile_gui.h +textfile_type.h +tgp.h +tile_cmd.h +tile_type.h +tilearea_type.h +tilehighlight_func.h +tilehighlight_type.h +tilematrix_type.hpp +timetable.h +toolbar_gui.h +town.h +town_type.h +townname_func.h +townname_type.h +track_func.h +track_type.h +train.h +transparency.h +transparency_gui.h +transport_type.h +tunnelbridge.h +vehicle_base.h +vehicle_func.h +vehicle_gui.h +vehicle_gui_base.h +vehicle_type.h +vehiclelist.h +viewport_func.h +viewport_sprite_sorter.h +viewport_type.h +watch_gui.h +water.h +waypoint_base.h +waypoint_func.h +widget_type.h +os/windows/win32.h +music/win32_m.h +sound/win32_s.h +video/win32_v.h +window_func.h +window_gui.h +window_type.h +zoom_func.h +zoom_type.h +#if WIN32 +#else +music/bemidi.h +music/cocoa_m.h +music/extmidi.h +music/libtimidity.h +music/os2_m.h +music/qtmidi.h +os/macosx/macos.h +os/macosx/osx_stdafx.h +os/macosx/splash.h +sound/cocoa_s.h +video/cocoa/cocoa_keys.h +video/cocoa/cocoa_v.h +#end + +# Core Source Code +core/alloc_func.cpp +core/alloc_func.hpp +core/alloc_type.hpp +core/backup_type.hpp +core/bitmath_func.cpp +core/bitmath_func.hpp +core/endian_func.hpp +core/endian_type.hpp +core/enum_type.hpp +core/geometry_func.cpp +core/geometry_func.hpp +core/geometry_type.hpp +core/math_func.cpp +core/math_func.hpp +core/mem_func.hpp +core/multimap.hpp +core/overflowsafe_type.hpp +core/pool_func.cpp +core/pool_func.hpp +core/pool_type.hpp +core/random_func.cpp +core/random_func.hpp +core/smallmap_type.hpp +core/smallmatrix_type.hpp +core/smallstack_type.hpp +core/smallvec_type.hpp +core/sort_func.hpp +core/string_compare_type.hpp + +# GUI Source Code +aircraft_gui.cpp +airport_gui.cpp +autoreplace_gui.cpp +bootstrap_gui.cpp +bridge_gui.cpp +build_vehicle_gui.cpp +cheat_gui.cpp +company_gui.cpp +console_gui.cpp +date_gui.cpp +departures_gui.cpp +depot_gui.cpp +dock_gui.cpp +engine_gui.cpp +error_gui.cpp +fios_gui.cpp +genworld_gui.cpp +goal_gui.cpp +graph_gui.cpp +group_gui.cpp +highscore_gui.cpp +industry_gui.cpp +intro_gui.cpp +linkgraph/linkgraph_gui.cpp +main_gui.cpp +misc_gui.cpp +music_gui.cpp +network/network_chat_gui.cpp +network/network_content_gui.cpp +network/network_gui.cpp +newgrf_debug_gui.cpp +newgrf_gui.cpp +news_gui.cpp +object_gui.cpp +order_gui.cpp +osk_gui.cpp +rail_gui.cpp +road_gui.cpp +roadveh_gui.cpp +settings_gui.cpp +ship_gui.cpp +signs_gui.cpp +smallmap_gui.cpp +station_gui.cpp +statusbar_gui.cpp +story_gui.cpp +subsidy_gui.cpp +terraform_gui.cpp +textfile_gui.cpp +timetable_gui.cpp +toolbar_gui.cpp +town_gui.cpp +train_gui.cpp +transparency_gui.cpp +tree_gui.cpp +vehicle_gui.cpp +viewport_gui.cpp +watch_gui.cpp +waypoint_gui.cpp + +# Widgets +widgets/airport_widget.h +widgets/ai_widget.h +widgets/autoreplace_widget.h +widgets/bootstrap_widget.h +widgets/bridge_widget.h +widgets/build_vehicle_widget.h +widgets/cheat_widget.h +widgets/company_widget.h +widgets/console_widget.h +widgets/date_widget.h +widgets/departures_widget.h +widgets/depot_widget.h +widgets/dock_widget.h +widgets/dropdown.cpp +widgets/dropdown_func.h +widgets/dropdown_type.h +widgets/dropdown_widget.h +widgets/engine_widget.h +widgets/error_widget.h +widgets/fios_widget.h +widgets/genworld_widget.h +widgets/goal_widget.h +widgets/graph_widget.h +widgets/group_widget.h +widgets/highscore_widget.h +widgets/industry_widget.h +widgets/intro_widget.h +widgets/link_graph_legend_widget.h +widgets/main_widget.h +widgets/misc_widget.h +widgets/music_widget.h +widgets/network_chat_widget.h +widgets/network_content_widget.h +widgets/network_widget.h +widgets/newgrf_debug_widget.h +widgets/newgrf_widget.h +widgets/news_widget.h +widgets/object_widget.h +widgets/order_widget.h +widgets/osk_widget.h +widgets/rail_widget.h +widgets/road_widget.h +widgets/settings_widget.h +widgets/sign_widget.h +widgets/smallmap_widget.h +widgets/station_widget.h +widgets/statusbar_widget.h +widgets/story_widget.h +widgets/subsidy_widget.h +widgets/terraform_widget.h +widgets/timetable_widget.h +widgets/toolbar_widget.h +widgets/town_widget.h +widgets/transparency_widget.h +widgets/tree_widget.h +widgets/vehicle_widget.h +widgets/viewport_widget.h +widgets/waypoint_widget.h + +# Command handlers +aircraft_cmd.cpp +autoreplace_cmd.cpp +clear_cmd.cpp +company_cmd.cpp +depot_cmd.cpp +group_cmd.cpp +industry_cmd.cpp +misc_cmd.cpp +object_cmd.cpp +order_cmd.cpp +rail_cmd.cpp +road_cmd.cpp +roadveh_cmd.cpp +ship_cmd.cpp +signs_cmd.cpp +station_cmd.cpp +terraform_cmd.cpp +timetable_cmd.cpp +town_cmd.cpp +train_cmd.cpp +tree_cmd.cpp +tunnelbridge_cmd.cpp +vehicle_cmd.cpp +void_cmd.cpp +water_cmd.cpp +waypoint_cmd.cpp + +# Save/Load handlers +saveload/afterload.cpp +saveload/ai_sl.cpp +saveload/airport_sl.cpp +saveload/animated_tile_sl.cpp +saveload/autoreplace_sl.cpp +saveload/cargomonitor_sl.cpp +saveload/cargopacket_sl.cpp +saveload/cheat_sl.cpp +saveload/company_sl.cpp +saveload/depot_sl.cpp +saveload/economy_sl.cpp +saveload/engine_sl.cpp +saveload/game_sl.cpp +saveload/gamelog_sl.cpp +saveload/goal_sl.cpp +saveload/group_sl.cpp +saveload/industry_sl.cpp +saveload/labelmaps_sl.cpp +saveload/linkgraph_sl.cpp +saveload/map_sl.cpp +saveload/misc_sl.cpp +saveload/newgrf_sl.cpp +saveload/newgrf_sl.h +saveload/object_sl.cpp +saveload/oldloader.cpp +saveload/oldloader.h +saveload/oldloader_sl.cpp +saveload/order_sl.cpp +saveload/saveload.cpp +saveload/saveload.h +saveload/saveload_filter.h +saveload/saveload_internal.h +saveload/signs_sl.cpp +saveload/station_sl.cpp +saveload/storage_sl.cpp +saveload/strings_sl.cpp +saveload/story_sl.cpp +saveload/subsidy_sl.cpp +saveload/town_sl.cpp +saveload/vehicle_sl.cpp +saveload/waypoint_sl.cpp + +# Tables +table/airport_defaults.h +table/airport_movement.h +table/airporttile_ids.h +table/airporttiles.h +table/animcursors.h +table/autorail.h +table/bridge_land.h +table/build_industry.h +table/cargo_const.h +table/clear_land.h +table/control_codes.h +table/elrail_data.h +table/engines.h +table/genland.h +table/heightmap_colours.h +table/industry_land.h +table/landscape_sprite.h +table/newgrf_debug_data.h +table/object_land.h +table/palette_convert.h +table/palettes.h +table/pricebase.h +table/railtypes.h +table/road_land.h +table/roadveh_movement.h +../objs/settings/table/settings.h +table/sprites.h +table/station_land.h +table/strgen_tables.h +../objs/langs/table/strings.h +table/town_land.h +table/townname.h +table/track_land.h +table/train_cmd.h +table/tree_land.h +table/unicode.h +table/water_land.h + +# MD5 +3rdparty/md5/md5.cpp +3rdparty/md5/md5.h + +# Script +script/script_config.cpp +script/script_config.hpp +script/script_fatalerror.hpp +script/script_info.cpp +script/script_info.hpp +script/script_info_dummy.cpp +script/script_instance.cpp +script/script_instance.hpp +script/script_scanner.cpp +script/script_scanner.hpp +script/script_storage.hpp +script/script_suspend.hpp +script/squirrel.cpp +script/squirrel.hpp +script/squirrel_class.hpp +script/squirrel_helper.hpp +script/squirrel_helper_type.hpp +script/squirrel_std.cpp +script/squirrel_std.hpp + +# Squirrel +3rdparty/squirrel/squirrel/sqapi.cpp +3rdparty/squirrel/squirrel/sqbaselib.cpp +3rdparty/squirrel/squirrel/sqclass.cpp +3rdparty/squirrel/squirrel/sqcompiler.cpp +3rdparty/squirrel/squirrel/sqdebug.cpp +3rdparty/squirrel/squirrel/sqfuncstate.cpp +3rdparty/squirrel/squirrel/sqlexer.cpp +3rdparty/squirrel/squirrel/sqmem.cpp +3rdparty/squirrel/squirrel/sqobject.cpp +3rdparty/squirrel/squirrel/sqstate.cpp +3rdparty/squirrel/sqstdlib/sqstdaux.cpp +3rdparty/squirrel/sqstdlib/sqstdmath.cpp +3rdparty/squirrel/squirrel/sqtable.cpp +3rdparty/squirrel/squirrel/sqvm.cpp + +# Squirrel headers +3rdparty/squirrel/squirrel/sqarray.h +3rdparty/squirrel/squirrel/sqclass.h +3rdparty/squirrel/squirrel/sqclosure.h +3rdparty/squirrel/squirrel/sqcompiler.h +3rdparty/squirrel/squirrel/sqfuncproto.h +3rdparty/squirrel/squirrel/sqfuncstate.h +3rdparty/squirrel/squirrel/sqlexer.h +3rdparty/squirrel/squirrel/sqobject.h +3rdparty/squirrel/squirrel/sqopcodes.h +3rdparty/squirrel/squirrel/sqpcheader.h +3rdparty/squirrel/squirrel/sqstate.h +3rdparty/squirrel/include/sqstdaux.h +3rdparty/squirrel/include/sqstdmath.h +3rdparty/squirrel/include/sqstdstring.h +3rdparty/squirrel/squirrel/sqstring.h +3rdparty/squirrel/squirrel/sqtable.h +3rdparty/squirrel/include/squirrel.h +3rdparty/squirrel/squirrel/squserdata.h +3rdparty/squirrel/squirrel/squtils.h +3rdparty/squirrel/squirrel/sqvm.h + +# AI Core +ai/ai.hpp +ai/ai_config.cpp +ai/ai_config.hpp +ai/ai_core.cpp +ai/ai_gui.cpp +ai/ai_gui.hpp +ai/ai_info.cpp +ai/ai_info.hpp +ai/ai_instance.cpp +ai/ai_instance.hpp +ai/ai_scanner.cpp +ai/ai_scanner.hpp + +# AI API +script/api/ai_changelog.hpp + +# Game API +script/api/game_changelog.hpp + +# Game Core +game/game.hpp +game/game_config.cpp +game/game_config.hpp +game/game_core.cpp +game/game_info.cpp +game/game_info.hpp +game/game_instance.cpp +game/game_instance.hpp +game/game_scanner.cpp +game/game_scanner.hpp +game/game_text.cpp +game/game_text.hpp + +# Script API +script/api/script_accounting.hpp +script/api/script_admin.hpp +script/api/script_airport.hpp +script/api/script_base.hpp +script/api/script_basestation.hpp +script/api/script_bridge.hpp +script/api/script_bridgelist.hpp +script/api/script_cargo.hpp +script/api/script_cargolist.hpp +script/api/script_cargomonitor.hpp +script/api/script_company.hpp +script/api/script_companymode.hpp +script/api/script_controller.hpp +script/api/script_date.hpp +script/api/script_depotlist.hpp +script/api/script_engine.hpp +script/api/script_enginelist.hpp +script/api/script_error.hpp +script/api/script_event.hpp +script/api/script_event_types.hpp +script/api/script_execmode.hpp +script/api/script_game.hpp +script/api/script_gamesettings.hpp +script/api/script_goal.hpp +script/api/script_group.hpp +script/api/script_grouplist.hpp +script/api/script_industry.hpp +script/api/script_industrylist.hpp +script/api/script_industrytype.hpp +script/api/script_industrytypelist.hpp +script/api/script_info_docs.hpp +script/api/script_infrastructure.hpp +script/api/script_list.hpp +script/api/script_log.hpp +script/api/script_map.hpp +script/api/script_marine.hpp +script/api/script_news.hpp +script/api/script_object.hpp +script/api/script_order.hpp +script/api/script_rail.hpp +script/api/script_railtypelist.hpp +script/api/script_road.hpp +script/api/script_sign.hpp +script/api/script_signlist.hpp +script/api/script_station.hpp +script/api/script_stationlist.hpp +script/api/script_story_page.hpp +script/api/script_storypagelist.hpp +script/api/script_storypageelementlist.hpp +script/api/script_subsidy.hpp +script/api/script_subsidylist.hpp +script/api/script_testmode.hpp +script/api/script_text.hpp +script/api/script_tile.hpp +script/api/script_tilelist.hpp +script/api/script_town.hpp +script/api/script_townlist.hpp +script/api/script_tunnel.hpp +script/api/script_types.hpp +script/api/script_vehicle.hpp +script/api/script_vehiclelist.hpp +script/api/script_viewport.hpp +script/api/script_waypoint.hpp +script/api/script_waypointlist.hpp +script/api/script_window.hpp + +# Script API Implementation +script/api/script_accounting.cpp +script/api/script_admin.cpp +script/api/script_airport.cpp +script/api/script_base.cpp +script/api/script_basestation.cpp +script/api/script_bridge.cpp +script/api/script_bridgelist.cpp +script/api/script_cargo.cpp +script/api/script_cargolist.cpp +script/api/script_cargomonitor.cpp +script/api/script_company.cpp +script/api/script_companymode.cpp +script/api/script_controller.cpp +script/api/script_date.cpp +script/api/script_depotlist.cpp +script/api/script_engine.cpp +script/api/script_enginelist.cpp +script/api/script_error.cpp +script/api/script_event.cpp +script/api/script_event_types.cpp +script/api/script_execmode.cpp +script/api/script_game.cpp +script/api/script_gamesettings.cpp +script/api/script_goal.cpp +script/api/script_group.cpp +script/api/script_grouplist.cpp +script/api/script_industry.cpp +script/api/script_industrylist.cpp +script/api/script_industrytype.cpp +script/api/script_industrytypelist.cpp +script/api/script_infrastructure.cpp +script/api/script_list.cpp +script/api/script_log.cpp +script/api/script_map.cpp +script/api/script_marine.cpp +script/api/script_news.cpp +script/api/script_object.cpp +script/api/script_order.cpp +script/api/script_rail.cpp +script/api/script_railtypelist.cpp +script/api/script_road.cpp +script/api/script_sign.cpp +script/api/script_signlist.cpp +script/api/script_station.cpp +script/api/script_stationlist.cpp +script/api/script_story_page.cpp +script/api/script_storypagelist.cpp +script/api/script_storypageelementlist.cpp +script/api/script_subsidy.cpp +script/api/script_subsidylist.cpp +script/api/script_testmode.cpp +script/api/script_text.cpp +script/api/script_tile.cpp +script/api/script_tilelist.cpp +script/api/script_town.cpp +script/api/script_townlist.cpp +script/api/script_tunnel.cpp +script/api/script_vehicle.cpp +script/api/script_vehiclelist.cpp +script/api/script_viewport.cpp +script/api/script_waypoint.cpp +script/api/script_waypointlist.cpp +script/api/script_window.cpp + +# Blitters +#if DEDICATED +#else +blitter/32bpp_anim.cpp +blitter/32bpp_anim.hpp +#if SSE +blitter/32bpp_anim_sse4.cpp +blitter/32bpp_anim_sse4.hpp +#end +blitter/32bpp_base.cpp +blitter/32bpp_base.hpp +blitter/32bpp_optimized.cpp +blitter/32bpp_optimized.hpp +blitter/32bpp_simple.cpp +blitter/32bpp_simple.hpp +#if SSE +blitter/32bpp_sse_func.hpp +blitter/32bpp_sse_type.h +blitter/32bpp_sse2.cpp +blitter/32bpp_sse2.hpp +blitter/32bpp_sse4.cpp +blitter/32bpp_sse4.hpp +blitter/32bpp_ssse3.cpp +blitter/32bpp_ssse3.hpp +#end +blitter/8bpp_base.cpp +blitter/8bpp_base.hpp +blitter/8bpp_optimized.cpp +blitter/8bpp_optimized.hpp +blitter/8bpp_simple.cpp +blitter/8bpp_simple.hpp +#end +blitter/base.cpp +blitter/base.hpp +blitter/factory.hpp +blitter/null.cpp +blitter/null.hpp + +# Drivers +music/music_driver.hpp +sound/sound_driver.hpp +video/video_driver.hpp + +# Sprite loaders +spriteloader/grf.cpp +spriteloader/grf.hpp +spriteloader/spriteloader.hpp + +# NewGRF +newgrf.cpp +newgrf_airport.cpp +newgrf_airporttiles.cpp +newgrf_canal.cpp +newgrf_cargo.cpp +newgrf_commons.cpp +newgrf_config.cpp +newgrf_engine.cpp +newgrf_generic.cpp +newgrf_house.cpp +newgrf_industries.cpp +newgrf_industrytiles.cpp +newgrf_object.cpp +newgrf_railtype.cpp +newgrf_sound.cpp +newgrf_spritegroup.cpp +newgrf_station.cpp +newgrf_storage.cpp +newgrf_text.cpp +newgrf_town.cpp +newgrf_townname.cpp + +# Map Accessors +bridge_map.cpp +bridge_map.h +clear_map.h +industry_map.h +object_map.h +rail_map.h +road_map.cpp +road_map.h +station_map.h +tile_map.h +town_map.h +tree_map.h +tunnel_map.cpp +tunnel_map.h +tunnelbridge_map.h +void_map.h +water_map.h + +# Misc +misc/array.hpp +misc/binaryheap.hpp +misc/blob.hpp +misc/countedobj.cpp +misc/countedptr.hpp +misc/dbg_helpers.cpp +misc/dbg_helpers.h +misc/fixedsizearray.hpp +misc/getoptdata.cpp +misc/getoptdata.h +misc/hashtable.hpp +misc/str.hpp + +# Network Core +network/core/address.cpp +network/core/address.h +network/core/config.h +network/core/core.cpp +network/core/core.h +network/core/game.h +network/core/host.cpp +network/core/host.h +network/core/os_abstraction.h +network/core/packet.cpp +network/core/packet.h +network/core/tcp.cpp +network/core/tcp.h +network/core/tcp_admin.cpp +network/core/tcp_admin.h +network/core/tcp_connect.cpp +network/core/tcp_content.cpp +network/core/tcp_content.h +network/core/tcp_game.cpp +network/core/tcp_game.h +network/core/tcp_http.cpp +network/core/tcp_http.h +network/core/tcp_listen.h +network/core/udp.cpp +network/core/udp.h + +# Pathfinder +pathfinder/follow_track.hpp +pathfinder/opf/opf_ship.cpp +pathfinder/opf/opf_ship.h +pathfinder/pathfinder_func.h +pathfinder/pathfinder_type.h +pathfinder/pf_performance_timer.hpp + +# NPF +pathfinder/npf/aystar.cpp +pathfinder/npf/aystar.h +pathfinder/npf/npf.cpp +pathfinder/npf/npf_func.h +pathfinder/npf/queue.cpp +pathfinder/npf/queue.h + +# YAPF +pathfinder/yapf/nodelist.hpp +pathfinder/yapf/yapf.h +pathfinder/yapf/yapf.hpp +pathfinder/yapf/yapf_base.hpp +pathfinder/yapf/yapf_cache.h +pathfinder/yapf/yapf_common.hpp +pathfinder/yapf/yapf_costbase.hpp +pathfinder/yapf/yapf_costcache.hpp +pathfinder/yapf/yapf_costrail.hpp +pathfinder/yapf/yapf_destrail.hpp +pathfinder/yapf/yapf_node.hpp +pathfinder/yapf/yapf_node_rail.hpp +pathfinder/yapf/yapf_node_road.hpp +pathfinder/yapf/yapf_node_ship.hpp +pathfinder/yapf/yapf_rail.cpp +pathfinder/yapf/yapf_road.cpp +pathfinder/yapf/yapf_ship.cpp +pathfinder/yapf/yapf_type.hpp + +# Video +video/dedicated_v.cpp +video/null_v.cpp +#if DEDICATED +#else +#if ALLEGRO + video/allegro_v.cpp +#end +#if SDL + video/sdl_v.cpp +#end +#if WIN32 + video/win32_v.cpp +#end +#if WINCE + video/win32_v.cpp +#end +#end + +# Music +#if DEDICATED +#else +#if ALLEGRO + music/allegro_m.cpp +#end +#if DIRECTMUSIC + music/dmusic.cpp +#end +#end +music/null_m.cpp +#if DEDICATED +#else +#if WIN32 + music/win32_m.cpp +#else + #if WINCE + #else + #if PSP + #else + #if DOS + #else + #if MORPHOS + #else + music/extmidi.cpp + #end + #end + #end + #end +#end +#if BEOS + music/bemidi.cpp +#end +#if LIBTIMIDITY + music/libtimidity.cpp +#end +#end + +# Sound +sound/null_s.cpp +#if DEDICATED +#else +#if ALLEGRO + sound/allegro_s.cpp +#end +#if SDL + sound/sdl_s.cpp +#end +#if WIN32 + sound/win32_s.cpp +#end +#end + +#if OSX +# OSX Files + os/macosx/macos.mm + + #if DEDICATED + #else + music/qtmidi.cpp + #end + + #if COCOA + video/cocoa/cocoa_v.mm + video/cocoa/event.mm + video/cocoa/fullscreen.mm + video/cocoa/wnd_quartz.mm + video/cocoa/wnd_quickdraw.mm + music/cocoa_m.cpp + sound/cocoa_s.cpp + os/macosx/splash.cpp + #end +#end + +# Windows files +#if WIN32 + os/windows/crashlog_win.cpp + os/windows/ottdres.rc + os/windows/win32.cpp +#end +#if WINCE + os/windows/ottdres.rc + os/windows/win32.cpp +#end + +# Threading +thread/thread.h +#if HAVE_THREAD + #if WIN32 + thread/thread_win32.cpp + #else + #if OS2 + thread/thread_os2.cpp + #else + #if MORPHOS + thread/thread_morphos.cpp + #else + thread/thread_pthread.cpp + #end + #end + #end +#else + thread/thread_none.cpp +#end diff --git a/config.lib b/config.lib new file mode 100644 index 0000000..8f1d13d --- /dev/null +++ b/config.lib @@ -0,0 +1,3709 @@ +# $Id$ + +# This file is part of OpenTTD. +# OpenTTD 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, version 2. +# OpenTTD 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 OpenTTD. If not, see . + +log() { + if [ $1 = "1" ]; then + shift + echo "$@" + else + shift + fi + echo "$@" >> $config_log +} + +set_default() { + ignore_extra_parameters="0" + # We set all kinds of defaults for params. Later on the user can override + # most of them; but if they don't, this default is used. + build="" + host="" + cc_build="" + cc_host="" + cxx_build="" + cxx_host="" + windres="" + strip="" + lipo="" + awk="awk" + os="DETECT" + endian="AUTO" + cpu_type="DETECT" + config_log="config.log" + prefix_dir="/usr/local" + binary_dir="games" + data_dir="share/games/openttd" + doc_dir="1" + icon_dir="share/pixmaps" + icon_theme_dir="1" + personal_dir="1" + shared_dir="1" + install_dir="/" + man_dir="1" + menu_dir="1" + menu_group="Game;" + menu_name="OpenTTD" + binary_name="openttd" + enable_debug="0" + enable_desync_debug="0" + enable_profiling="0" + enable_lto="0" + enable_dedicated="0" + enable_network="1" + enable_static="1" + enable_translator="0" + enable_unicode="1" + enable_console="1"; + enable_assert="0" + enable_strip="1" + enable_universal="0" + enable_osx_g5="0" + enable_cocoa_quartz="1" + enable_cocoa_quickdraw="1" + with_osx_sysroot="1" + with_application_bundle="1" + with_menu_entry="1" + with_allegro="1" + with_sdl="1" + with_cocoa="1" + with_zlib="1" + with_lzma="1" + with_lzo2="1" + with_xdg_basedir="1" + with_png="1" + enable_builtin_depend="1" + with_makedepend="0" + with_direct_music="1" + with_sort="1" + with_iconv="1" + with_midi="" + with_midi_arg="" + with_libtimidity="1" + with_freetype="1" + with_fontconfig="1" + with_icu="1" + static_icu="0" + with_psp_config="1" + with_threads="1" + with_distcc="1" + with_ccache="1" + with_nforenum="1" + with_grfcodec="1" + with_sse="1" + + save_params_array=" + build + host + cc_build + cc_host + cxx_build + cxx_host + windres + strip + lipo + awk + os + endian + cpu_type + config_log + prefix_dir + binary_dir + data_dir + doc_dir + icon_dir + icon_theme_dir + man_dir + menu_dir + personal_dir + shared_dir + install_dir + menu_group + menu_name + binary_name + enable_debug + enable_desync_debug + enable_profiling + enable_lto + enable_dedicated + enable_network + enable_static + enable_translator + enable_unicode + enable_console + enable_assert + enable_strip + enable_universal + enable_osx_g5 + enable_cocoa_quartz + enable_cocoa_quickdraw + with_osx_sysroot + with_application_bundle + with_allegro + with_sdl + with_cocoa + with_zlib + with_lzma + with_lzo2 + with_xdg_basedir + with_png + enable_builtin_depend + with_makedepend + with_direct_music + with_sort + with_iconv + with_midi + with_midi_arg + with_libtimidity + with_freetype + with_fontconfig + with_icu + static_icu + with_psp_config + with_threads + with_distcc + with_ccache + with_grfcodec + with_nforenum + with_sse + CC CXX CFLAGS CXXFLAGS LDFLAGS CFLAGS_BUILD CXXFLAGS_BUILD LDFLAGS_BUILD" +} + +detect_params() { + # Walk over all params from the user and override any default settings if + # needed. This also handles any invalid option. + for p in "$@"; do + if [ -n "$prev_p" ]; then + eval "$prev_p=\$p" + prev_p= + continue + fi + + optarg=`expr "x$p" : 'x[^=]*=\(.*\)'` + + case "$p" in + --help | -h | -\?) showhelp; exit 0;; + + --config-log) prev_p="config_log";; + --config-log=*) config_log="$optarg";; + + --build) prev_p="build";; + --build=*) build="$optarg";; + + --host) prev_p="host";; + --host=*) host="$optarg";; + + --os) prev_p="os";; + --os=*) os="$optarg";; + + --cpu-type) prev_p="cpu_type";; + --cpu-type=*) cpu_type="$optarg";; + + --cc-build) prev_p="cc_build";; + --cc-build=*) cc_build="$optarg";; + --cc-host) prev_p="cc_host";; + --cc-host=*) cc_host="$optarg";; + --cxx-build) prev_p="cxx_build";; + --cxx-build=*) cxx_build="$optarg";; + --cxx-host) prev_p="cxx_host";; + --cxx-host=*) cxx_host="$optarg";; + --windres) prev_p="windres";; + --windres=*) windres="$optarg";; + --awk) prev_p="awk";; + --awk=*) awk="$optarg";; + --strip) prev_p="strip";; + --strip=*) strip="$optarg";; + --lipo) prev_p="lipo";; + --lipo=*) lipo="$optarg";; + + --endian) prev_p="endian";; + --endian=*) endian="$optarg";; + + + + # Alias --prefix with --prefix-dir, for compatibility with GNU autotools + --prefix-dir | --prefix) prev_p="prefix_dir";; + --prefix-dir=* | --prefix=*) prefix_dir="$optarg";; + + --binary-dir) prev_p="binary_dir";; + --binary-dir=*) binary_dir="$optarg";; + + --data-dir) prev_p="data_dir";; + --data-dir=*) data_dir="$optarg";; + + --doc-dir) prev_p="doc_dir";; + --doc-dir=*) doc_dir="$optarg";; + + --icon-dir) prev_p="icon_dir";; + --icon-dir=*) icon_dir="$optarg";; + + --icon-theme-dir) prev_p="icon_theme_dir";; + --icon-theme-dir=*) icon_theme_dir="$optarg";; + --without-icon-theme) icon_theme_dir="";; + + --menu-dir) prev_p="menu_dir";; + --menu-dir=*) menu_dir="$optarg";; + --without-menu-entry) menu_dir="";; + + --menu-name) prev_p="menu_name";; + --menu-name=*) menu_name="$optarg";; + + --binary-name) prev_p="binary_name";; + --binary-name=*) binary_name="$optarg";; + + --man-dir) prev_p="man_dir";; + --man-dir=*) man_dir="$optarg";; + + --personal-dir) prev_p="personal_dir";; + --personal-dir=*) personal_dir="$optarg";; + --without-personal-dir) personal_dir="";; + + --shared-dir) prev_p="shared_dir";; + --shared-dir=*) shared_dir="$optarg";; + --without-shared-dir) shared_dir="";; + + --install-dir) prev_p="install_dir";; + --install-dir=*) install_dir="$optarg";; + + + + --menu-group) prev_p="menu_group";; + --menu-group=*) menu_group="$optarg";; + + + + --enable-debug) enable_debug="1";; + --enable-debug=*) enable_debug="$optarg";; + --enable-desync-debug) enable_desync_debug="1";; + --enable-desync-debug=*) enable_desync_debug="$optarg";; + --enable-profiling) enable_profiling="1";; + --enable-profiling=*) enable_profiling="$optarg";; + --enable-lto) enable_lto="1";; + --enable-lto=*) enable_lto="$optarg";; + --enable-ipo) enable_lto="1";; + --enable-ipo=*) enable_lto="$optarg";; + --enable-dedicated) enable_dedicated="1";; + --enable-dedicated=*) enable_dedicated="$optarg";; + --enable-network) enable_network="2";; + --enable-network=*) enable_network="$optarg";; + --disable-network) enable_network="0";; + --disable-static) enable_static="0";; + --enable-static) enable_static="2";; + --enable-static=*) enable_static="$optarg";; + --disable-translator) enable_translator="0";; + --enable-translator) enable_translator="2";; + --enable-translator=*) enable_translator="$optarg";; + --disable-assert) enable_assert="0";; + --enable-assert) enable_assert="2";; + --enable-assert=*) enable_assert="$optarg";; + --disable-strip) enable_strip="0";; + --enable-strip) enable_strip="2";; + --enable-strip=*) enable_strip="$optarg";; + --disable-universal) enable_universal="0";; + --enable-universal) enable_universal="i386 ppc";; + --enable-universal=*) enable_universal="$optarg";; + --disable-osx-g5) enable_osx_g5="0";; + --enable-osx-g5) enable_osx_g5="2";; + --enable-osx-g5=*) enable_osx_g5="$optarg";; + --disable-unicode) enable_unicode="0";; + --enable-unicode) enable_unicode="2";; + --enable-unicode=*) enable_unicode="$optarg";; + --disable-console) enable_console="0";; + --enable-console) enable_console="2";; + --enable-console=*) enable_console="$optarg";; + + --disable-cocoa-quartz) enable_cocoa_quartz="0";; + --enable-cocoa-quartz) enable_cocoa_quartz="2";; + --enable-cocoa-quartz=*) enable_cocoa_quartz="$optarg";; + --disable-cocoa-quickdraw) enable_cocoa_quickdraw="0";; + --enable-cocoa-quickdraw) enable_cocoa_quickdraw="2";; + --enable-cocoa-quickdraw=*) enable_cocoa_quickdraw="$optarg";; + + --with-allegro) with_allegro="2";; + --without-allegro) with_allegro="0";; + --with-allegro=*) with_allegro="$optarg";; + + --with-sdl) with_sdl="2";; + --without-sdl) with_sdl="0";; + --with-sdl=*) with_sdl="$optarg";; + + --with-cocoa) with_cocoa="2";; + --without-cocoa) with_cocoa="0";; + --with-cocoa=*) with_cocoa="$optarg";; + + --with-zlib) with_zlib="2";; + --without-zlib) with_zlib="0";; + --with-zlib=*) with_zlib="$optarg";; + + --with-lzma) with_lzma="2";; + --without-lzma) with_lzma="0";; + --with-lzma=*) with_lzma="$optarg";; + --with-liblzma) with_lzma="2";; + --without-liblzma) with_lzma="0";; + --with-liblzma=*) with_lzma="$optarg";; + + --with-lzo2) with_lzo2="2";; + --without-lzo2) with_lzo2="0";; + --with-lzo2=*) with_lzo2="$optarg";; + --with-liblzo2) with_lzo2="2";; + --without-liblzo2) with_lzo2="0";; + --with-liblzo2=*) with_lzo2="$optarg";; + + --with-xdg-basedir) with_xdg_basedir="2";; + --without-xdg-basedir) with_xdg_basedir="0";; + --with-xdg-basedir=*) with_xdg_basedir="$optarg";; + --with-libxdg-basedir) with_xdg_basedir="2";; + --without-libxdg-basedir) with_xdg_basedir="0";; + --with-libxdg-basedir=*) with_xdg_basedir="$optarg";; + + --with-png) with_png="2";; + --without-png) with_png="0";; + --with-png=*) with_png="$optarg";; + --with-libpng) with_png="2";; + --without-libpng) with_png="0";; + --with-libpng=*) with_png="$optarg";; + + --with-libtimidity) with_libtimidity="2";; + --without-libtimidity) with_libtimidity="0";; + --with-libtimidity=*) with_libtimidity="$optarg";; + + --with-freetype) with_freetype="2";; + --without-freetype) with_freetype="0";; + --with-freetype=*) with_freetype="$optarg";; + --with-libfreetype) with_freetype="2";; + --without-libfreetype) with_freetype="0";; + --with-libfreetype=*) with_freetype="$optarg";; + + --with-fontconfig) with_fontconfig="2";; + --without-fontconfig) with_fontconfig="0";; + --with-fontconfig=*) with_fontconfig="$optarg";; + --with-libfontconfig) with_fontconfig="2";; + --without-libfontconfig) with_fontconfig="0";; + --with-libfontconfig=*) with_fontconfig="$optarg";; + + --with-icu) with_icu="2";; + --without-icu) with_icu="0";; + --with-icu=*) with_icu="$optarg";; + --with-libicu) with_icu="2";; + --without-libicu) with_icu="0";; + --with-libicu=*) with_icu="$optarg";; + --static-icu) static_icu="1";; + --static-icu=*) static_icu="$optarg";; + --static-libicu) static_icu="1";; + --static-libicu=*) static_icu="$optarg";; + + --with-psp-config) with_psp_config="2";; + --without-psp-config) with_psp_config="0";; + --with-psp-config=*) with_psp_config="$optarg";; + + --disable-builtin-depend) enable_builtin_depend="0";; + --enable-builtin-depend) enable_builtin_depend="2";; + --enable-builtin-depend=*) enable_builtin_depend="$optarg";; + + --with-makedepend) with_makedepend="2";; + --without-makedepend) with_makedepend="0";; + --with-makedepend=*) with_makedepend="$optarg";; + + --with-direct-music) with_direct_music="2";; + --without-direct-music) with_direct_music="0";; + --with-direct-music=*) with_direct_music="$optarg";; + + --with-sort) with_sort="2";; + --without-sort) with_sort="0";; + --with-sort=*) with_sort="$optarg";; + + --with-iconv) with_iconv="2";; + --without-iconv) with_iconv="0";; + --with-iconv=*) with_iconv="$optarg";; + + --with-midi=*) with_midi="$optarg";; + --with-midi-arg=*) with_midi_arg="$optarg";; + + --without-distcc) with_distcc="0";; + --with-distcc) with_distcc="2";; + --with-distcc=*) with_distcc="$optarg";; + + --without-ccache) with_ccache="0";; + --with-ccache) with_ccache="2";; + --with-ccache=*) with_ccache="$optarg";; + + --without-nforenum) with_nforenum="0";; + --with-nforenum) with_nforenum="2";; + --with-nforenum=*) with_nforenum="$optarg";; + + --without-grfcodec) with_grfcodec="0";; + --with-grfcodec) with_grfcodec="2";; + --with-grfcodec=*) with_grfcodec="$optarg";; + + --without-osx-sysroot) with_osx_sysroot="0";; + --with-osx-sysroot) with_osx_sysroot="2";; + --with-osx-sysroot=*) with_osx_sysroot="$optarg";; + + --without-application-bundle) with_application_bundle="0";; + --with-application-bundle) with_application_bundle="1";; + --with-application-bundle=*) with_application_bundle="$optarg";; + + --without-threads) with_threads="0";; + --with-threads) with_threads="1";; + --with-threads=*) with_threads="$optarg";; + + --without-sse) with_sse="0";; + --with-sse) with_sse="1";; + --with-sse=*) with_sse="$optarg";; + + CC=* | --CC=*) CC="$optarg";; + CXX=* | --CXX=*) CXX="$optarg";; + CFLAGS=* | --CFLAGS=*) CFLAGS="$optarg";; + CXXFLAGS=* | --CXXFLAGS=*) CXXFLAGS="$optarg";; + LDFLAGS=* | --LDFLAGS=*) LDFLAGS="$optarg";; + CFLAGS_BUILD=* | --CFLAGS_BUILD=* | --CFLAGS-BUILD=*) CFLAGS_BUILD="$optarg";; + CXXFLAGS_BUILD=* | --CXXFLAGS_BUILD=* | --CXXFLAGS-BUILD=*) CXXFLAGS_BUILD="$optarg";; + LDFLAGS_BUILD=* | --LDFLAGS_BUILD=* | --LDFLAGS-BUILD=*) LDFLAGS_BUILD="$optarg";; + + --ignore-extra-parameters) ignore_extra_parameters="1";; + + --* | -*) + if [ "$ignore_extra_parameters" = "0" ]; then + log 1 "Unknown option $p" + exit 1 + else + log 1 "Unknown option $p ignored" + fi + ;; + esac + done + + if [ -n "$prev_p" ]; then + log 1 "configure: error: missing argument to --$prev_p" + exit 1 + fi + + # Clean the logfile + echo "" > $config_log + log 2 "Invocation: $0 $*" +} + +save_params() { + # Here we save all params, so we can later on do an exact redo of this + # configuration, without having the user to re-input stuff + + echo "Running configure with following options:" >> $config_log + echo "" >> $config_log + + configure="$CONFIGURE_EXECUTABLE --ignore-extra-parameters" + for p in $save_params_array; do + eval "v=\"\$$p\"" + p=`echo "$p" | sed 's@_@-@g;s@\n@@g;s@ @\\ @g'` + # Only save those params that aren't empty + configure="$configure --$p=\"$v\"" + done + + echo "$configure" >> $config_log + echo "$configure" > config.cache + echo "" >> $config_log +} + +check_params() { + # Some params want to be in full uppercase, else they might not work as + # expected.. fix that here + + endian=`echo $endian | tr '[a-z]' '[A-Z]'` + os=`echo $os | tr '[a-z]' '[A-Z]'` + cpu_type=`echo $cpu_type | tr '[a-z]' '[A-Z]'` + + # Check if all params have valid values + + # Endian only allows AUTO, LE and, BE + if [ -z "`echo $endian | egrep '^(AUTO|LE|BE|PREPROCESSOR)$'`" ]; then + log 1 "configure: error: invalid option --endian=$endian" + log 1 " Available options are: --endian=[AUTO|LE|BE]" + exit 1 + fi + if [ "$endian" = "PREPROCESSOR" ] && [ "$os" != "OSX" ]; then + log 1 "configure: error: invalid option --endian=$endian" + log 1 " PREPROCESSOR is only available for OSX" + exit 1 + fi + # OS only allows DETECT, UNIX, OSX, FREEBSD, DRAGONFLY, OPENBSD, NETBSD, MORPHOS, BEOS, HAIKU, SUNOS, CYGWIN, MINGW, OS2, DOS, WINCE, and PSP + if [ -z "`echo $os | egrep '^(DETECT|UNIX|OSX|FREEBSD|DRAGONFLY|OPENBSD|NETBSD|HPUX|MORPHOS|BEOS|HAIKU|SUNOS|CYGWIN|MINGW|OS2|DOS|WINCE|PSP)$'`" ]; then + log 1 "configure: error: invalid option --os=$os" + log 1 " Available options are: --os=[DETECT|UNIX|OSX|FREEBSD|DRAGONFLY|OPENBSD|NETBSD|HPUX|MORPHOS|BEOS|HAIKU|SUNOS|CYGWIN|MINGW|OS2|DOS|WINCE|PSP]" + exit 1 + fi + # cpu_type can be either 32 or 64 + if [ -z "`echo $cpu_type | egrep '^(32|64|DETECT)$'`" ]; then + log 1 "configure: error: invalid option --cpu-type=$cpu_type" + log 1 " Available options are: --cpu-type[=DETECT|32|64]" + exit 1 + fi + # enable_debug should be between 0 and 4 + if [ -z "`echo $enable_debug | egrep '^[0123]$'`" ]; then + log 1 "configure: error: invalid option --enable-debug=$enable_debug" + log 1 " Available options are: --enable-debug[=0123]" + exit 1 + fi + + # enable_desync_debug should be between 0 and 3 + if [ -z "`echo $enable_desync_debug | egrep '^[012]$'`" ]; then + log 1 "configure: error: invalid option --enable-desync-debug=$enable_desync_debug" + log 1 " Available options are: --enable-desync-debug[=012]" + exit 1 + fi + + detect_awk + + detect_os + + check_build + check_host + + # Check for universal builds; they only make sense for OSX, so fail if enabled for another OS + if [ "$enable_universal" = "0" ]; then + log 1 "checking universal build... no" + else + if [ "$os" != "OSX" ]; then + log 1 "configure: error: --enable-universal only works on OSX" + exit 1 + fi + log 1 "checking universal build... yes, for: $enable_universal" + fi + + # Already detected by check_build + log 1 "checking build cc... $cc_build" + log 1 "checking host cc... $cc_host" + + check_cxx_build + check_cxx_host + check_windres + if [ "$enable_strip" != "0" ]; then + check_strip + else + log 1 "checking strip... disabled" + fi + check_lipo + + if [ "$enable_builtin_depend" != "0" ]; then + log 1 "checking builtin depend... yes" + makedepend="\$(SRC_OBJS_DIR)/\$(DEPEND)" + else + log 1 "checking builtin depend... no" + fi + + check_makedepend + detect_cputype + detect_sse_capable_architecture + + if [ "$enable_static" = "1" ]; then + if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "MORPHOS" ] || [ "$os" = "DOS" ]; then + enable_static="2" + else + enable_static="0" + fi + fi + + if [ "$enable_static" != "0" ]; then + log 1 "checking static... yes" + + if [ "$os" != "MINGW" ] && [ "$os" != "CYGWIN" ] && [ "$os" != "OSX" ] && [ "$os" != "MORPHOS" ] && [ "$os" != "DOS" ]; then + log 1 "WARNING: static is only known to work on Windows, DOS, MacOSX and MorphOS" + log 1 "WARNING: use static at your own risk on this platform" + + sleep 5 + fi + else + log 1 "checking static... no" + fi + + if [ "$enable_unicode" = "1" ]; then + if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "DOS" ]; then + enable_unicode="2" + else + enable_unicode="0" + fi + fi + + if [ "$enable_unicode" != "0" ]; then + log 1 "checking unicode... yes" + else + log 1 "checking unicode... no" + fi + + # Show what we configured + if [ "$enable_debug" = "0" ]; then + log 1 "using debug level... no" + elif [ "$enable_profiling" != "0" ]; then + log 1 "using debug level... profiling (debug level $enable_debug)" + else + log 1 "using debug level... level $enable_debug" + fi + + if [ "$enable_desync_debug" = "0" ]; then + log 1 "using desync debug level... no" + else + log 1 "using desync debug level... level $enable_desync_debug" + log 1 "WARNING: desync debug functions slow down the game considerably." + log 1 "WARNING: use only when you are instructed to do so" + log 1 " or when you know what you are doing." + + sleep 5 + fi + + if [ "$enable_lto" != "0" ]; then + # GCC 4.5 outputs '%{flto}', GCC 4.6 outputs '%{flto*}' + has_lto=`($cxx_build -dumpspecs 2>&1 | grep '\%{flto') || ($cxx_build -help ipo 2>&1 | grep '\-ipo')` + if [ -n "$has_lto" ]; then + log 1 "using link time optimization... yes" + else + enable_lto="0" + log 1 "using link time optimization... no" + log 1 "WARNING: you selected link time optimization but it is not found." + sleep 5 + fi + else + log 1 "using link time optimization... no" + fi + + + if [ "$os" != "OSX" ] && [ "$with_osx_sysroot" != "0" ]; then + if [ "$with_osx_sysroot" = "1" ]; then + with_osx_sysroot="0" + + log 1 "checking OSX sysroot... not OSX, skipping" + else + log 1 "configure: error: --with-osx-sysroot only works if OSX is the target" + exit 1 + fi + fi + + if [ "$with_osx_sysroot" != "0" ]; then + if [ "$enable_universal" = "0" ] && [ "$with_osx_sysroot" != "1" ] && [ "$with_osx_sysroot" != "2" ]; then + # Sysroot manually specified? Check for usability + log 1 "checking OSX sysroot... $with_osx_sysroot" + if ! check_osx_sdk "$with_osx_sysroot"; then + log 1 "Passed sysroot not found/not functional" + exit 1 + fi + else + # If autodetect and no universal, use system default + if [ "$with_osx_sysroot" = "1" ] && [ "$enable_universal" = "0" ]; then + log 1 "checking OSX sysroot... no (use system default)" + else + log 1 "checking OSX sysroot... automatically" + detect_osx_sdk + fi + fi + + if [ -n "$osx_sdk_path" ]; then + if [ "$enable_universal" != "0" ]; then + if [ -z "$osx_sdk_104_path" ]; then + log 1 "WARNING: Could not find a usable 10.4u SDK, the resulting" + log 1 "WARNING: binary will only run on OSX 10.5 or later" + osx_sdk_104_path="$osx_sdk_path" + fi + OSX_SYSROOT="-isysroot $osx_sdk_104_path" + OSX_LD_SYSROOT="-Wl,-syslibroot,$osx_sdk_104_path" + else + OSX_SYSROOT="-isysroot $osx_sdk_path" + OSX_LD_SYSROOT="-Wl,-syslibroot,$osx_sdk_path" + fi + fi + else + if [ "$os" = "OSX" ]; then + log 1 "checking OSX sysroot... no (use system default)" + fi + fi + + detect_allegro + detect_sdl + detect_cocoa + + if [ "$enable_dedicated" != "0" ]; then + log 1 "checking GDI video driver... dedicated server, skipping" + log 1 "checking dedicated... found" + + if [ "$enable_network" = "0" ]; then + log 1 "configure: error: building a dedicated server without network support is pointless" + exit 1 + fi + else + if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "WINCE" ]; then + log 1 "checking GDI video driver... found" + else + log 1 "checking GDI video driver... not Windows, skipping" + fi + + if [ -z "$allegro_config" ] && [ -z "$sdl_config" ] && [ "$with_cocoa" = 0 ] && [ "$os" != "MINGW" ] && [ "$os" != "CYGWIN" ] && [ "$os" != "WINCE" ]; then + log 1 "configure: error: no video driver development files found" + log 1 " If you want a dedicated server use --enable-dedicated as parameter" + exit 1 + else + log 1 "checking dedicated... not selected" + fi + fi + + if [ "$os" != "MINGW" ] && [ "$os" != "CYGWIN" ]; then + log 1 "checking console application... not Windows, skipping" + elif [ "$enable_console" = "1" ] && [ "$enable_dedicated" != "0" ]; then + log 1 "checking console application... dedicated server, enabled" + enable_console="2" + elif [ "$enable_console" = "1" ]; then + log 1 "checking console application... disabled (only used when forced)" + enable_console="0" + elif [ "$enable_console" = "0" ]; then + log 1 "checking console application... disabled" + else + log 1 "checking console application... enabled" + fi + + if [ "$enable_network" = "1" ] && [ "$os" = "DOS" ]; then + log 1 "checking network... DOS, skipping" + enable_network=0 + elif [ "$enable_network" != "0" ]; then + log 1 "checking network... found" + else + log 1 "checking network... disabled" + fi + + log 1 "checking squirrel... found" + SCRIPT_SRC_DIR="$ROOT_DIR/src/3rdparty/squirrel/include" + + if [ "$enable_translator" != "0" ]; then + log 1 "checking translator... debug" + # -t shows TODO items, normally they are muted + strgen_flags="-t" + else + log 1 "checking translator... no" + strgen_flags="" + fi + + if [ "$enable_assert" != "0" ]; then + log 1 "checking assert... enabled" + else + log 1 "checking assert... disabled" + fi + + pre_detect_with_zlib=$with_zlib + detect_zlib + + if [ "$with_zlib" = "0" ] || [ -z "$zlib" ]; then + log 1 "WARNING: zlib was not detected or disabled" + log 1 "WARNING: OpenTTD doesn't require zlib, but it does mean that many features" + log 1 "WARNING: (like loading most old savegames/scenarios, loading heightmaps," + log 1 "WARNING: using PNG, or using fonts, ...) will be disabled." + if [ "$pre_detect_with_zlib" = "0" ]; then + log 1 "WARNING: We strongly suggest you to install zlib." + else + log 1 "configure: error: no zlib detected" + log 1 " If you want to compile without zlib use --without-zlib as parameter" + exit + fi + fi + + pre_detect_with_lzma=$with_lzma + detect_lzma + + if [ "$with_lzma" = "0" ] || [ -z "$lzma_config" ]; then + log 1 "WARNING: lzma was not detected or disabled" + log 1 "WARNING: OpenTTD doesn't require lzma, but it does mean that many features" + log 1 "WARNING: (like loading most savegames/scenarios and joining most servers)" + log 1 "WARNING: will be disabled." + if [ "$pre_detect_with_lzma" = "0" ]; then + log 1 "WARNING: We strongly suggest you to install liblzma." + log 1 "configure: error: no liblzma detected" + else + log 1 " If you want to compile without lzma use --without-lzma as parameter" + exit + fi + fi + + pre_detect_with_lzo2=$with_lzo2 + detect_lzo2 + + if [ "$with_lzo2" = "0" ] || [ -z "$lzo2" ]; then + log 1 "WARNING: liblzo2 was not detected or disabled" + log 1 "WARNING: OpenTTD doesn't require liblzo2, but it does mean that" + log 1 "WARNING: loading old savegames/scenarios will be disabled." + if [ "$pre_detect_with_lzo2" = "0" ]; then + log 1 "WARNING: We strongly suggest you to install liblzo2." + else + log 1 "configure: error: no liblzo2 detected" + log 1 " If you want to compile without liblzo2 use --without-liblzo2 as parameter" + exit + fi + fi + + detect_xdg_basedir + detect_png + detect_freetype + detect_fontconfig + detect_icu + detect_pspconfig + detect_libtimidity + + if [ "$with_direct_music" != "0" ]; then + if [ "$os" != "MINGW" ] && [ "$os" != "CYGWIN" ]; then + if [ "$with_direct_music" != "1" ]; then + log 1 "configure: error: direct-music is only supported on Win32 targets" + exit 1 + fi + with_direct_music="0" + + log 1 "checking direct-music... not Windows, skipping" + else + check_direct_music + fi + fi + + detect_sort + + if [ "$os" = "OSX" ] && [ "$endian" = "AUTO" ]; then + endian="PREPROCESSOR" + fi + + log 1 "checking endianness... $endian" + + # Suppress language errors when there is a version defined, indicating a release + # It just isn't pretty if any release produces warnings in the languages. + if [ -f "$ROOT_DIR/version" ]; then + lang_suppress="yes" + log 1 "suppress language errors... yes" + else + lang_suppress="" + log 1 "suppress language errors... no" + fi + + if [ "$enable_debug" = "0" ] && [ "$enable_profiling" = "0" ] && [ "$enable_strip" != "0" ]; then + if [ "$os" = "MORPHOS" ]; then + strip_arg="--strip-all --strip-unneeded --remove-section .comment" + elif [ "$os" = "OSX" ]; then + strip_arg="" + elif [ "$os" = "OS2" ]; then + strip_arg="" + # OS2 uses strip via gcc, because it needs to be feed to emxbind + LDFLAGS="$LDFLAGS -s" + elif [ "$os" = "SUNOS" ]; then + # The GNU strip does know -s, the non-GNU doesn't + # So try to detect it (in a bit of an ugly way) + strip_arg="`$strip -s strip.test 2>/dev/null && echo \"-s\"`" + else + strip_arg="-s" + fi + + log 1 "checking stripping... $strip $strip_arg" + else + strip="" + log 1 "checking stripping... skipped" + fi + + if [ "$with_distcc" = "0" ]; then + log 1 "checking distcc... no" + elif [ "$with_distcc" = "1" ]; then + with_distcc="0" + + log 1 "checking distcc... no (only used when forced)" + elif [ "$with_distcc" = "2" ]; then + distcc="distcc" + else + distcc="$with_distcc" + fi + if [ "$with_distcc" != "0" ]; then + res="`$distcc --version 2>/dev/null | head -n 1 | cut -b 1-6`" + if [ "$res" != "distcc" ]; then + distcc="" + log 1 "checking distcc... no" + if [ "$with_distcc" = "2" ]; then + log 1 "configure: error: no distcc detected, but was forced to be used" + exit 1 + fi + if [ "$with_distcc" != "1" ]; then + log 1 "configure: error: '$with_distcc' doesn't seem a distcc to me" + exit 1 + fi + fi + + log 1 "checking distcc... $distcc" + fi + + if [ "$with_ccache" = "0" ]; then + log 1 "checking ccache... no" + elif [ "$with_ccache" = "1" ]; then + with_ccache="0" + + log 1 "checking ccache... no (only used when forced)" + elif [ "$with_ccache" = "2" ]; then + ccache="ccache" + else + ccache="$with_ccache" + fi + if [ "$with_ccache" != "0" ]; then + res="`$ccache --version 2>/dev/null | head -n 1 | cut -b 1-6`" + if [ "$res" != "ccache" ]; then + ccache="" + log 1 "checking ccache... no" + if [ "$with_ccache" = "2" ]; then + log 1 "configure: error: no ccache detected, but was forced to be used" + exit 1 + fi + if [ "$with_ccache" != "1" ]; then + log 1 "configure: error: '$with_ccache' doesn't seem a ccache to me" + exit 1 + fi + fi + + log 1 "checking ccache... $ccache" + fi + + detect_grfcodec + detect_nforenum + + if [ -z "$grfcodec" ] && [ -n "$nforenum" ]; then + log 1 "checking nforenum/grfcodec... nforenum needs grfcodec enabled, disabling nforenum" + nforenum="" + fi + + if [ -z "$nforenum" ] && [ -n "$grfcodec" ]; then + log 1 "checking nforenum/grfcodec... grfcodec needs nforenum enabled, disabling grfcodec" + grfcodec="" + fi + + if [ "$os" = "DOS" ]; then + with_threads="0" + fi + + if [ "$os" != "OSX" ] && [ "$with_application_bundle" != "0" ]; then + if [ "$with_application_bundle" = "1" ]; then + with_application_bundle="0" + + log 1 "checking OSX application bundle... not OSX, skipping" + else + log 1 "configure: error: --with-application-bundle only works if OSX is the target" + exit 1 + fi + fi + + if [ "$os" = "OSX" ] && [ "$with_application_bundle" = "1" ]; then + OSXAPP="OpenTTD.app" + else + OSXAPP="" + fi + + if [ "$os" = "OSX" ]; then + # Test on ppc970 (G5) - we can optimize there + + if [ "$enable_osx_g5" != "0" ]; then + log 1 "detecting ppc970 (G5)... yes (forced)" + else + # First, are we a real OSX system, else we can't detect it + native=`LC_ALL=C uname | tr '[A-Z]' '[a-z]' | grep darwin` + # If $host doesn't match $build , we are cross-compiling + if [ -n "$native" ] && [ "$build" = "$host" ]; then + $cxx_build $SRC_DIR/os/macosx/G5_detector.cpp -o G5_detector + res=`./G5_detector` + rm -f G5_detector + if [ -n "$res" ]; then + # This is G5, add flags for it + enable_osx_g5="2" + + log 1 "detecting ppc970 (G5)... yes" + else + enable_osx_g5="0" + + log 1 "detecting ppc970 (G5)... no" + fi + else + enable_osx_g5="0" + + log 1 "detecting ppc970 (G5)... no (cross-compiling)" + fi + fi + else + if [ "$enable_osx_g5" != "0" ]; then + log 1 "configure: error: ppc970 (OSX G5) selected, but not compiling for OSX" + log 1 "configure: error: either select OSX as OS, or deselect ppc970" + + exit 1 + fi + fi + + if [ -d "$ROOT_DIR/.svn" ] && [ -n "`svn help 2>/dev/null`" ]; then + log 1 "checking revision... svn detection" + elif [ -d "$ROOT_DIR/../.svn" ] && [ -n "`svn help 2>/dev/null`" ] && [ -n "`LC_ALL=C svn info $ROOT_DIR/.. | grep '^URL:.*tags$'`" ]; then + # subversion changed its behaviour; now not all folders have a .svn folder, + # but only the root folder. Since making tags requires a (sparse) checkout + # of the tags folder, the folder of the tag does not have a .svn folder + # anymore and this fails to detect the subversion repository checkout. + log 1 "checking revision... svn detection (tag)" + elif [ -d "$ROOT_DIR/.git" ] && [ -n "`git help 2>/dev/null`" ]; then + log 1 "checking revision... git detection" + elif [ -d "$ROOT_DIR/.hg" ] && [ -n "`HGPLAIN= hg help 2>/dev/null`" ]; then + log 1 "checking revision... hg detection" + elif [ -f "$ROOT_DIR/.ottdrev" ]; then + log 1 "checking revision... source tarball" + else + log 1 "checking revision... no detection" + log 1 "WARNING: there is no means to determine the version." + log 1 "WARNING: please use a subversion, mercurial, or git checkout of OpenTTD." + log 1 "WARNING: you can only join game servers that have been compiled without" + log 1 "WARNING: version detection." + log 1 "WARNING: there is a great chance you desync." + log 1 "WARNING: USE WITH CAUTION!" + + sleep 5 + fi + + if [ "$doc_dir" = "1" ]; then + if [ "$os" = "UNIX" ] || [ "$os" = "FREEBSD" ] || [ "$os" = "DRAGONFLY" ] || [ "$os" = "OPENBSD" ] || [ "$os" = "NETBSD" ] || [ "$os" = "HPUX" ] || [ "$os" = "SUNOS" ]; then + doc_dir="share/doc/openttd" + else + doc_dir="$data_dir/docs" + fi + else + doc_dir="`echo $doc_dir | sed 's@\([^\]\)\\\\ @\1\\\\\\\\ @g;s@\([^\]\) @\1\\\\\\\\ @g'`" + fi + + if [ "$icon_theme_dir" = "1" ]; then + if [ "$os" = "UNIX" ] || [ "$os" = "FREEBSD" ] || [ "$os" = "DRAGONFLY" ] || [ "$os" = "OPENBSD" ] || [ "$os" = "NETBSD" ] || [ "$os" = "HPUX" ] || [ "$os" = "SUNOS" ]; then + icon_theme_dir="share/icons/hicolor" + else + icon_theme_dir="" + fi + else + icon_theme_dir="`echo $icon_theme_dir | sed 's@\([^\]\)\\\\ @\1\\\\\\\\ @g;s@\([^\]\) @\1\\\\\\\\ @g'`" + fi + + if [ "$personal_dir" = "1" ]; then + if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "WINCE" ] || [ "$os" = "DOS" ] || [ "$os" = "HAIKU" ]; then + personal_dir="OpenTTD" + elif [ "$os" = "OSX" ]; then + personal_dir="Documents/OpenTTD" + else + personal_dir=".openttd" + fi + else + personal_dir="`echo $personal_dir | sed 's@\([^\]\)\\\\ @\1\\\\\\\\ @g;s@\([^\]\) @\1\\\\\\\\ @g'`" + fi + + if [ "$shared_dir" = "1" ]; then + # we are using default values + if [ "$os" = "OSX" ]; then + shared_dir="/Library/Application\\\\ Support/OpenTTD" + else + shared_dir="" + fi + else + shared_dir="`echo $shared_dir | sed 's@\([^\]\)\\\\ @\1\\\\\\\\ @g;s@\([^\]\) @\1\\\\\\\\ @g'`" + fi + + if [ "$man_dir" = "1" ]; then + # add manpage on UNIX systems + if [ "$os" = "UNIX" ] || [ "$os" = "FREEBSD" ] || [ "$os" = "DRAGONFLY" ] || [ "$os" = "OPENBSD" ] || [ "$os" = "NETBSD" ] || [ "$os" = "HPUX" ] || [ "$os" = "SUNOS" ] || [ "$os" = "OSX" ]; then + man_dir="share/man/man6" + else + man_dir="" + fi + else + man_dir="`echo $man_dir | sed 's@\([^\]\)\\\\ @\1\\\\\\\\ @g;s@\([^\]\) @\1\\\\\\\\ @g'`" + fi + + if [ "$menu_dir" = "1" ]; then + # add a freedesktop menu item only for some UNIX systems + if [ "$os" = "UNIX" ] || [ "$os" = "FREEBSD" ] || [ "$os" = "DRAGONFLY" ] || [ "$os" = "OPENBSD" ] || [ "$os" = "NETBSD" ] || [ "$os" = "HPUX" ] || [ "$os" = "SUNOS" ]; then + menu_dir="share/applications" + else + menu_dir="" + fi + else + menu_dir="`echo $menu_dir | sed 's@\([^\]\)\\\\ @\1\\\\\\\\ @g;s@\([^\]\) @\1\\\\\\\\ @g'`" + fi + + detect_iconv + + if [ -n "$personal_dir" ] + then + log 1 "personal home directory... $personal_dir" + else + log 1 "personal home directory... none" + fi + + if [ -n "$shared_dir" ] + then + log 1 "shared data directory... $shared_dir" + else + log 1 "shared data directory... none" + fi + + if [ -n "$install_dir" ] + then + log 1 "installation directory... $install_dir" + else + log 1 "installation directory... none" + fi + + if [ -n "$icon_theme_dir" ] + then + log 1 "icon theme directory... $icon_theme_dir" + else + log 1 "icon theme directory... none" + fi + + if [ -n "$man_dir" ] + then + log 1 "manual page directory... $man_dir" + else + log 1 "manual page directory... none" + fi + + if [ -n "$menu_dir" ] + then + log 1 "menu item directory... $menu_dir" + else + log 1 "menu item directory... none" + fi +} + +make_compiler_cflags() { + # Params: + # $1 - compiler + # $2 - name of the cflags variable + # $3 - name of the cxxflags variable + # $4 - name of the ldflags variable + # $5 - name of the features variable + + eval eval "flags=\\\$$2" + eval eval "cxxflags=\\\$$3" + eval eval "ldflags=\\\$$4" + eval eval "features=\\\$$5" + + if [ `basename $1 | cut -c 1-3` = "icc" ]; then + # Enable some things only for certain ICC versions + cc_version=`$1 -dumpversion | cut -c 1-4 | sed s@\\\.@@g` + + flags="$flags -rdynamic" + ldflags="$ldflags -rdynamic" + + if [ -z "$first_time_icc_check" ]; then + first_time_icc_check=no + if [ $cc_version -lt 90 ]; then + log 1 "WARNING: you seem to be using a very old version of ICC" + log 1 "WARNING: OpenTTD hasn't been tested with this version" + sleep 5 + elif [ $cc_version -lt 120 ]; then + log 1 "WARNING: you seem to be using an unsupported ICC version" + log 1 "WARNING: ICC older than 12.0 is known to fail to compile OpenTTD" + sleep 5 + fi + fi + + flags="$flags -Wall" + # remark #111: statement is unreachable + flags="$flags -wd111" + # remark #181: argument is incompatible with corresponding format string conversion + # ICC is very picky about signedness of operands, warnings provided by GCC are enough + flags="$flags -wd181" + # remark #271: trailing comma is nonstandard + flags="$flags -wd271" + # remark #280: selector expression is constant + flags="$flags -wd280" + # remark #304: access control not specified ("public" by default) + flags="$flags -wd304" + # remark #383: value copied to temporary, reference to temporary used + flags="$flags -wd383" + # remark #444: destructor for base class ... is not virtual + flags="$flags -wd444" + # remark #593: variable ... was set but never used + flags="$flags -wd593" + # warning #654: overloaded virtual function ... is only partially overridden in class ... + flags="$flags -wd654" + # remark #810: conversion from ... to ... may lose significant bits + flags="$flags -wd810" + # remark #869: parameter ... was never referenced + flags="$flags -wd869" + # warning #873: function ... ::operator new ... has no corresponding operator delete ... + flags="$flags -wd873" + # remark #981: operands are evaluated in unspecified order + flags="$flags -wd981" + # remark #1418: external function definition with no prior declaration + flags="$flags -wd1418" + # remark #1419: external declaration in primary source file + flags="$flags -wd1419" + # remark #1572: floating-point equality and inequality + flags="$flags -wd1572" + # remark #1599: declaration hides variable/parameter ... + flags="$flags -wd1599" + # remark #1720: function ... ::operator new ... has no corresponding member operator delete ... + flags="$flags -wd1720" + + if [ $cc_version -lt 110 ]; then + # warns about system headers with recent glibc: + # warning #1292: attribute "__nonnull__" ignored + flags="$flags -wd1292" + fi + + if [ $cc_version -ge 100 ]; then + # warning #1899: multicharacter character literal (potential portability problem) + flags="$flags -wd1899" + # vec report defaults to telling where it did loop vectorisation, which is not very important + flags="$flags -vec-report=0 " + fi + + if [ $cc_version -ge 110 ]; then + # remark #2259: non-pointer conversion from ... to ... may lose significant bits + flags="$flags -wd2259" + # Use c++0x mode so static_assert() is available + cxxflags="$cxxflags -std=c++0x" + fi + + if [ "$enable_lto" != "0" ]; then + has_ipo=`$1 -help ipo | grep '\-ipo'` + if [ -n "$has_ipo" ]; then + # Use IPO (only if we see IPO exists and is requested) + flags="$flags -ipo" + features="$features lto" + fi + fi + elif [ `basename $1 | grep 'clang'` ]; then + # Enable some things only for certain clang versions + cc_version="`$1 -v 2>&1 | head -n 1 | sed s@[^0-9]@@g | cut -c 1-2`" + + # aliasing rules are not held in openttd code + flags="$flags -fno-strict-aliasing" + + # -W alone doesn't enable all warnings enabled by -Wall; on the other hand, + # -Weverything enables too many useless warnings that can't be disabled (as of 3.0) + flags="$flags -Wall -W" + + # warning: unused parameter '...' + flags="$flags -Wno-unused-parameter" + + # warning: expression result unused + flags="$flags -Wno-unused-value" + + # warning: multi-character character constant + flags="$flags -Wno-multichar" + + # warning: explicitly assigning a variable of type '...' to itself + # it happens when using the FOR_ALL_WINDOWS_FROM_BACK_FROM macro + flags="$flags -Wno-self-assign" + + if [ "$cc_version" -lt "30" ]; then + # warning: equality comparison with extraneous parentheses + flags="$flags -Wno-parentheses" + # warning: operands of ? are integers of different signs: 'unsigned int' and 'int' + flags="$flags -Wno-sign-compare" + fi + + if [ "$cc_version" -ge "30" ]; then + # warning: equality comparison with extraneous parentheses + # this warning could be useful, but it warns about code in squirrel + flags="$flags -Wno-parentheses-equality" + fi + + if [ "$with_ccache" != "0" -o "$with_distcc" != "0" ]; then + # ccache and distcc run separate preprocess and compile passes, + # both are fed with the same CFLAGS. Unfortunately, clang + # complains about -I when compiling preprocessed files: + # "clang: warning: argument unused during compilation: '-I /usr/include'" + flags="$flags -Qunused-arguments" + fi + + if [ "$enable_assert" -eq "0" ]; then + # do not warn about unused variables when building without asserts + flags="$flags -Wno-unused-variable" + fi + + # rdynamic is used to get useful stack traces from crash reports. + ldflags="$ldflags -rdynamic" + else + # Enable some things only for certain GCC versions + cc_version=`$1 -dumpversion | cut -c 1,3` + + if [ $cc_version -lt 33 ]; then + log 1 "configure: error: gcc older than 3.3 can't compile OpenTTD because of its poor template support" + exit 1 + fi + + flags="$flags -Wall -Wno-multichar -Wsign-compare -Wundef" + flags="$flags -Wwrite-strings -Wpointer-arith" + flags="$flags -W -Wno-unused-parameter -Wredundant-decls" + flags="$flags -Wformat=2 -Wformat-security" + + if [ $enable_assert -eq 0 ]; then + # Do not warn about unused variables when building without asserts + flags="$flags -Wno-unused-variable" + if [ $cc_version -ge 46 ]; then + # GCC 4.6 gives more warnings, disable them too + flags="$flags -Wno-unused-but-set-variable" + flags="$flags -Wno-unused-but-set-parameter" + fi + fi + + if [ $cc_version -ge 34 ]; then + # Warn when a variable is used to initialise itself: + # int a = a; + flags="$flags -Winit-self" + fi + + if [ $cc_version -ge 40 ]; then + # GCC 4.0+ complains about that we break strict-aliasing. + # On most places we don't see how to fix it, and it doesn't + # break anything. So disable strict-aliasing to make the + # compiler all happy. + flags="$flags -fno-strict-aliasing" + # Warn about casting-out 'const' with regular C-style cast. + # The preferred way is const_cast<>() which doesn't warn. + flags="$flags -Wcast-qual" + fi + + if [ $cc_version -ge 42 ]; then + # GCC 4.2+ automatically assumes that signed overflows do + # not occur in signed arithmetics, whereas we are not + # sure that they will not happen. It furthermore complains + # about its own optimized code in some places. + flags="$flags -fno-strict-overflow" + # GCC 4.2 no longer includes -Wnon-virtual-dtor in -Wall. + # Enable it in order to be consistent with older GCC versions. + flags="$flags -Wnon-virtual-dtor" + fi + + if [ $cc_version -ge 43 ]; then + # Use gnu++0x mode so static_assert() is available. + # Don't use c++0x, it breaks mingw (with gcc 4.4.0). + cxxflags="$cxxflags -std=gnu++0x" + fi + + if [ $cc_version -eq 45 ]; then + # Prevent optimisation supposing enums are in a range specified by the standard + # For details, see http://gcc.gnu.org/PR43680 + flags="$flags -fno-tree-vrp" + fi + + if [ $cc_version -ge 47 ]; then + # Disable -Wnarrowing which gives many warnings, such as: + # warning: narrowing conversion of '...' from 'unsigned int' to 'int' inside { } [-Wnarrowing] + # They are valid according to the C++ standard, but useless. + cxxflags="$cxxflags -Wno-narrowing" + # Disable bogus 'attempt to free a non-heap object' warning + flags="$flags -Wno-free-nonheap-object" + fi + + if [ "$enable_lto" != "0" ]; then + # GCC 4.5 outputs '%{flto}', GCC 4.6 outputs '%{flto*}' + has_lto=`$1 -dumpspecs | grep '\%{flto'` + if [ -n "$has_lto" ]; then + # Use LTO only if we see LTO exists and is requested + if [ $cc_version -lt 46 ]; then + flags="$flags -flto" + else + flags="$flags -flto=jobserver" + fi + ldflags="$ldflags -fwhole-program" + features="$features lto" + fi + fi + + has_rdynamic=`$1 -dumpspecs | grep rdynamic` + if [ -n "$has_rdynamic" ]; then + # rdynamic is used to get useful stack traces from crash reports. + flags="$flags -rdynamic" + ldflags="$ldflags -rdynamic" + fi + fi + + eval "$2=\"$flags\"" + eval "$3=\"$cxxflags\"" + eval "$4=\"$ldflags\"" + eval "$5=\"$features\"" +} + +make_cflags_and_ldflags() { + # General CFlags for BUILD + CFLAGS_BUILD="$CFLAGS_BUILD" + # Special CXXFlags for BUILD + CXXFLAGS_BUILD="$CXXFLAGS_BUILD" + # LDFLAGS for BUILD + LDFLAGS_BUILD="$LDFLAGS_BUILD" + # FEATURES for BUILD (lto) + FEATURES_BUILD="" + # General CFlags for HOST + CFLAGS="$CFLAGS" + # Special CXXFlags for HOST + CXXFLAGS="$CXXFLAGS" + # Libs to compile. In fact this is just LDFLAGS + LIBS="-lstdc++" + # LDFLAGS used for HOST + LDFLAGS="$LDFLAGS" + # FEATURES for HOST (lto) + FEATURES="" + + make_compiler_cflags "$cc_build" "CFLAGS_BUILD" "CXXFLAGS_BUILD" "LDFLAGS_BUILD" "FEATURES_BUILD" + make_compiler_cflags "$cc_host" "CFLAGS" "CXXFLAGS" "LDFLAGS" "FEATURES" + + CFLAGS="$CFLAGS -D$os" + CFLAGS_BUILD="$CFLAGS_BUILD -D$os" + + if [ "$enable_debug" = "0" ]; then + # No debug, add default stuff + OBJS_SUBDIR="release" + if [ "$os" = "MORPHOS" ]; then + CFLAGS="-I/gg/os-include -noixemul -fstrict-aliasing -fexpensive-optimizations -mcpu=604 -fno-inline -mstring -mmultiple $CFLAGS" + LDFLAGS="$LDFLAGS -noixemul" + fi + + if [ "$enable_profiling" = "0" ]; then + # -fomit-frame-pointer and -pg do not go well together (gcc errors they are incompatible) + CFLAGS="-fomit-frame-pointer $CFLAGS" + fi + CFLAGS="-O2 $CFLAGS" + else + OBJS_SUBDIR="debug" + + # Each debug level reduces the optimization by a bit + if [ $enable_debug -ge 1 ]; then + CFLAGS="$CFLAGS -g -D_DEBUG" + if [ "$os" = "PSP" ]; then + CFLAGS="$CFLAGS -G0" + fi + fi + if [ $enable_debug -ge 2 ]; then + CFLAGS="$CFLAGS -fno-inline" + fi + if [ $enable_debug -ge 3 ]; then + CFLAGS="$CFLAGS -O0" + else + CFLAGS="$CFLAGS -O2" + fi + fi + + if [ $enable_debug -le 2 ]; then + cc_host_is_gcc=`basename "$cc_host" | grep "gcc" &>/dev/null` + if [ -n "$cc_host_is_gcc" ]; then + # Define only when compiling with GCC. Some GLIBC versions use GNU + # extensions in a way that breaks build with at least ICC. + # This requires -O1 or more, so debug level 3 (-O0) is excluded. + CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2" + fi + + cc_build_is_gcc=`basename "$cc_build" | grep "gcc" &>/dev/null` + if [ -n "$cc_build_is_gcc" ]; then + # Just add -O1 to the tools needed for building. + CFLAGS_BUILD="$CFLAGS_BUILD -D_FORTIFY_SOURCE=2 -O1" + fi + fi + + if [ "$os" = "OSX" ] && [ $cc_version -eq 40 ]; then + # Apple's GCC 4.0 has a compiler bug for x86_64 with (higher) optimization, + # wrongly optimizing ^= in loops. This disables the failing optimisation. + CFLAGS="$CFLAGS -fno-expensive-optimizations" + fi + + if [ "$enable_profiling" != "0" ]; then + CFLAGS="$CFLAGS -pg" + LDFLAGS="$LDFLAGS -pg" + fi + + if [ "$with_threads" = "0" ]; then + CFLAGS="$CFLAGS -DNO_THREADS" + fi + if [ "$with_sse" = "1" ]; then + CFLAGS="$CFLAGS -DWITH_SSE" + fi + + if [ "`echo $1 | cut -c 1-3`" != "icc" ]; then + if [ "$os" = "CYGWIN" ]; then + flags="$flags -mwin32" + LDFLAGS="$LDFLAGS -mwin32" + fi + if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ]; then + if [ $cc_version -lt 46 ]; then + flags="$flags -mno-cygwin" + LDFLAGS="$LDFLAGS -mno-cygwin" + fi + + if [ "$enable_console" != "0" ]; then + LDFLAGS="$LDFLAGS -Wl,--subsystem,console" + else + LDFLAGS="$LDFLAGS -Wl,--subsystem,windows" + fi + + LIBS="$LIBS -lws2_32 -lwinmm -lgdi32 -ldxguid -lole32 -limm32" + + if [ $cc_version -ge 44 ]; then + LDFLAGS_BUILD="$LDFLAGS_BUILD -static-libgcc -static-libstdc++" + fi + if [ $cc_version -ge 47 ]; then + CFLAGS="$CFLAGS -mno-ms-bitfields" + fi + fi + fi + + if [ "$os" != "CYGWIN" ] && [ "$os" != "HAIKU" ] && [ "$os" != "OPENBSD" ] && [ "$os" != "MINGW" ] && [ "$os" != "MORPHOS" ] && [ "$os" != "OSX" ] && [ "$os" != "DOS" ] && [ "$os" != "WINCE" ] && [ "$os" != "PSP" ] && [ "$os" != "OS2" ]; then + LIBS="$LIBS -lpthread" + fi + + if [ "$os" != "CYGWIN" ] && [ "$os" != "HAIKU" ] && [ "$os" != "MINGW" ] && [ "$os" != "DOS" ] && [ "$os" != "WINCE" ]; then + LIBS="$LIBS -lc" + fi + if [ "$os" = "WINCE" ]; then + LIBS="$LIBS -lcoredll -lcorelibc -laygshell -lws2 -e WinMainCRTStartup" + fi + if [ "$os" = "PSP" ]; then + CFLAGS="$CFLAGS -I`$psp_config -p`/include" + LDFLAGS="$LDFLAGS -L`$psp_config -p`/lib" + + CFLAGS="$CFLAGS -fno-exceptions -fno-rtti -D_PSP_FW_VERSION=150" + LIBS="$LIBS -D_PSP_FW_VERSION=150 -lpspdebug -lpspdisplay -lpspge -lpspctrl -lpspsdk -lpspnet -lpspnet_inet -lpspnet_apctl -lpspnet_resolver -lpsputility -lpspuser -lpspkernel -lm" + fi + + if [ "$os" = "MORPHOS" ]; then + # -Wstrict-prototypes generates much noise because of system headers + CFLAGS="$CFLAGS -Wno-strict-prototypes" + fi + + if [ "$os" = "OPENBSD" ]; then + LIBS="$LIBS -pthread" + fi + + if [ "$os" = "OSX" ]; then + LDFLAGS="$LDFLAGS -framework Cocoa" + + # Add macports include dir which is not always set a default system dir. This avoids zillions of bogus warnings. + CFLAGS="$CFLAGS -isystem/opt/local/include" + + if [ "$enable_dedicated" = "0" ] && ([ "$cpu_type" = "32" ] || [ "$enable_universal" != "0" ]); then + LIBS="$LIBS -framework QuickTime" + else + CFLAGS="$CFLAGS -DNO_QUICKTIME" + fi + + if [ "$enable_universal" = "0" ]; then + # Universal builds set this elsewhere + CFLAGS="$OSX_SYSROOT $CFLAGS" + LDFLAGS="$OSX_LD_SYSROOT $LDFLAGS" + fi + + if [ "$enable_universal" = "0" ] && [ $cc_version -gt 40 ]; then + # Only set the min version when not doing an universal build. + # Universal builds set the version elsewhere. + if [ "$cpu_type" = "64" ]; then + CFLAGS="$CFLAGS -mmacosx-version-min=10.5" + else + gcc_cpu=`$cc_host -dumpmachine` + if [ "`echo $gcc_cpu | cut -c 1-3`" = "ppc" -o "`echo $gcc_cpu | cut -c 1-7`" = "powerpc" ]; then + # PowerPC build can run on 10.3 + CFLAGS="$CFLAGS -mmacosx-version-min=10.3" + else + # Intel is only available starting from 10.4 + CFLAGS="$CFLAGS -mmacosx-version-min=10.4" + fi + fi + fi + fi + + if [ "$os" = "BEOS" ] || [ "$os" = "HAIKU" ]; then + LIBS="$LIBS -lmidi -lbe" + fi + + # Most targets act like UNIX, just with some additions + if [ "$os" = "BEOS" ] || [ "$os" = "HAIKU" ] || [ "$os" = "OSX" ] || [ "$os" = "MORPHOS" ] || [ "$os" = "FREEBSD" ] || [ "$os" = "DRAGONFLY" ] || [ "$os" = "OPENBSD" ] || [ "$os" = "NETBSD" ] || [ "$os" = "HPUX" ] || [ "$os" = "SUNOS" ] || [ "$os" = "OS2" ]; then + CFLAGS="$CFLAGS -DUNIX" + fi + # And others like Windows + if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "WINCE" ]; then + CFLAGS="$CFLAGS -DWIN" + fi + + if [ -n "$allegro_config" ]; then + CFLAGS="$CFLAGS -DWITH_ALLEGRO" + CFLAGS="$CFLAGS `$allegro_config --cflags`" + if [ "$os" != "MINGW" ] && [ "$os" != "CYGWIN" ] && [ "$os" != "WINCE" ]; then + if [ "$enable_static" != "0" ]; then + LIBS="$LIBS `$allegro_config --static --libs`" + else + LIBS="$LIBS `$allegro_config --libs`" + fi + fi + fi + + if [ -n "$sdl_config" ]; then + CFLAGS="$CFLAGS -DWITH_SDL" + # SDL must not add _GNU_SOURCE as it breaks many platforms + CFLAGS="$CFLAGS `$sdl_config --cflags | sed 's@-D_GNU_SOURCE[^ ]*@@'`" + if [ "$os" != "MINGW" ] && [ "$os" != "CYGWIN" ] && [ "$os" != "WINCE" ]; then + if [ "$enable_static" != "0" ]; then + LIBS="$LIBS `$sdl_config --static-libs`" + else + LIBS="$LIBS `$sdl_config --libs`" + fi + fi + fi + + if [ "$with_cocoa" != "0" ]; then + CFLAGS="$CFLAGS -DWITH_COCOA" + LIBS="$LIBS -F/System/Library/Frameworks -framework Cocoa -framework Carbon -framework AudioUnit -framework AudioToolbox" + + if [ "$enable_cocoa_quartz" != "0" ]; then + CFLAGS="$CFLAGS -DENABLE_COCOA_QUARTZ" + fi + + if [ "$enable_cocoa_quickdraw" != "0" ]; then + CFLAGS="$CFLAGS -DENABLE_COCOA_QUICKDRAW" + fi + fi + + if [ "$with_zlib" != "0" ]; then + if [ "$enable_static" != "0" ] && [ "$os" != "OSX" ]; then + LIBS="$LIBS $zlib" + else + LIBS="$LIBS -lz" + fi + CFLAGS="$CFLAGS -DWITH_ZLIB" + fi + + if [ -n "$lzma_config" ]; then + CFLAGS="$CFLAGS -DWITH_LZMA" + CFLAGS="$CFLAGS `$lzma_config --cflags | tr '\n\r' ' '`" + + if [ "$enable_static" != "0" ]; then + CFLAGS="$CFLAGS -DLZMA_API_STATIC" + LIBS="$LIBS `$lzma_config --libs --static | tr '\n\r' ' '`" + else + LIBS="$LIBS `$lzma_config --libs | tr '\n\r' ' '`" + fi + fi + + if [ "$with_lzo2" != "0" ]; then + if [ "$enable_static" != "0" ] && [ "$os" != "OSX" ]; then + LIBS="$LIBS $lzo2" + else + LIBS="$LIBS -llzo2" + fi + CFLAGS="$CFLAGS -DWITH_LZO" + fi + + if [ -n "$xdg_basedir_config" ]; then + CFLAGS="$CFLAGS -DWITH_XDG_BASEDIR" + CFLAGS="$CFLAGS `$xdg_basedir_config --cflags | tr '\n\r' ' '`" + + if [ "$enable_static" != "0" ]; then + LIBS="$LIBS `$xdg_basedir_config --libs --static | tr '\n\r' ' '`" + else + LIBS="$LIBS `$xdg_basedir_config --libs | tr '\n\r' ' '`" + fi + fi + + # 64bit machines need -D_SQ64 + if [ "$cpu_type" = "64" ] && [ "$enable_universal" = "0" ]; then + CFLAGS="$CFLAGS -D_SQ64" + fi + CFLAGS="$CFLAGS -I$SCRIPT_SRC_DIR" + + if [ -n "$png_config" ]; then + CFLAGS="$CFLAGS -DWITH_PNG" + CFLAGS="$CFLAGS `$png_config --cflags | tr '\n\r' ' '`" + + if [ "$enable_static" != "0" ]; then + if [ "$os" = "OSX" ]; then + # fontconfig_config goes via pkg-config on all systems, which doesn't know --prefix + # Also, despite the reason we link to the .a file ourself (because we can't use -static), we do need to ask pkg-config about possible other deps + LIBS="$LIBS `$png_config --variable=prefix`/lib/libpng.a `$png_config --libs --static | sed s@-lpng[0-9]*@@`" + else + LIBS="$LIBS `$png_config --libs --static | tr '\n\r' ' '`" + fi + else + LIBS="$LIBS `$png_config --libs | tr '\n\r' ' '`" + fi + fi + + if [ -n "$fontconfig_config" ]; then + CFLAGS="$CFLAGS -DWITH_FONTCONFIG" + CFLAGS="$CFLAGS `$fontconfig_config --cflags | tr '\n\r' ' '`" + + if [ "$enable_static" != "0" ]; then + if [ "$os" = "OSX" ]; then + # fontconfig_config goes via pkg-config on all systems, which doesn't know --prefix + # Also, despite the reason we link to the .a file ourself (because we can't use -static), we do need to ask pkg-config about possible other deps + LIBS="$LIBS `$fontconfig_config --variable=prefix`/lib/libfontconfig.a `$fontconfig_config --libs --static | sed s@-lfontconfig@@`" + else + LIBS="$LIBS `$fontconfig_config --libs --static | tr '\n\r' ' '`" + fi + else + LIBS="$LIBS `$fontconfig_config --libs | tr '\n\r' ' '`" + fi + fi + + if [ -n "$freetype_config" ]; then + CFLAGS="$CFLAGS -DWITH_FREETYPE" + CFLAGS="$CFLAGS `$freetype_config --cflags | tr '\n\r' ' '`" + + if [ "$enable_static" != "0" ]; then + if [ "$os" = "OSX" ]; then + LIBS="$LIBS `$freetype_config --prefix`/lib/libfreetype.a" + else + # Is it possible to do static with freetype, if so: how? + LIBS="$LIBS `$freetype_config --libs | tr '\n\r' ' '`" + fi + else + LIBS="$LIBS `$freetype_config --libs | tr '\n\r' ' '`" + fi + fi + + if [ -n "$icu_config" ]; then + CFLAGS="$CFLAGS -DWITH_ICU" + CFLAGS="$CFLAGS `$icu_config --cppflags | tr '\n\r' ' '`" + + # Some icu-configs have the 'feature' of not adding a space where others do add the space + if [ "$static_icu" != "0" ]; then + LIBS="$LIBS `$icu_config --ldflags-searchpath` `($icu_config --ldflags-libsonly; $icu_config --ldflags-layout) | tr '\n\r' ' ' | sed s/licu/lsicu/g`" + else + LIBS="$LIBS `$icu_config --ldflags-searchpath` `($icu_config --ldflags-libsonly; $icu_config --ldflags-layout) | tr '\n\r' ' '`" + fi + fi + + + if [ "$with_direct_music" != "0" ]; then + CFLAGS="$CFLAGS -DWIN32_ENABLE_DIRECTMUSIC_SUPPORT" + # GCC 4.0+ doesn't like the DirectX includes (gives tons of + # warnings on it we won't be able to fix). For now just + # suppress those warnings. + if [ $cc_version -ge 40 ]; then + CFLAGS="$CFLAGS -Wno-non-virtual-dtor" + fi + fi + + if [ -n "$libtimidity" ]; then + if [ "$enable_static" != "0" ]; then + LIBS="$LIBS $libtimidity" + else + LIBS="$LIBS -ltimidity" + fi + CFLAGS="$CFLAGS -DLIBTIMIDITY" + fi + + if [ "$with_iconv" != "0" ]; then + CFLAGS="$CFLAGS -DWITH_ICONV" + if [ "$link_to_iconv" = "yes" ]; then + LIBS="$LIBS -liconv" + if [ "$with_iconv" != "2" ]; then + CFLAGS="$CFLAGS -I$with_iconv/include" + LIBS="$LIBS -L$with_iconv/lib" + fi + fi + + if [ "$os" != "OSX" ] && [ "$have_non_const_iconv" != "no" ]; then + CFLAGS="$CFLAGS -DHAVE_NON_CONST_ICONV" + fi + fi + + if [ -n "$with_midi" ]; then + CFLAGS="$CFLAGS -DEXTERNAL_PLAYER=\\\\\"$with_midi\\\\\"" + fi + if [ -n "$with_midi_arg" ]; then + CFLAGS="$CFLAGS -DMIDI_ARG=\\\\\"$with_midi_arg\\\\\"" + fi + + if [ "$enable_dedicated" != "0" ]; then + CFLAGS="$CFLAGS -DDEDICATED" + fi + + if [ "$enable_unicode" != "0" ]; then + CFLAGS="$CFLAGS -DUNICODE -D_UNICODE" + fi + + if [ "$enable_network" != "0" ]; then + CFLAGS="$CFLAGS -DENABLE_NETWORK" + + if [ "$os" = "BEOS" ]; then + LDFLAGS="$LDFLAGS -lbind -lsocket" + fi + + if [ "$os" = "HAIKU" ]; then + LDFLAGS="$LDFLAGS -lnetwork" + fi + + if [ "$os" = "SUNOS" ]; then + LDFLAGS="$LDFLAGS -lnsl -lsocket" + fi + fi + + if [ "$enable_static" != "0" ]; then + # OSX can't handle -static in LDFLAGS + if [ "$os" != "OSX" ]; then + LDFLAGS="$LDFLAGS -static" + fi + fi + + if [ "$enable_assert" = "0" ]; then + CFLAGS="$CFLAGS -DNDEBUG" + CFLAGS_BUILD="$CFLAGS_BUILD -DNDEBUG" + fi + + if [ "$enable_desync_debug" != "0" ]; then + CFLAGS="$CFLAGS -DRANDOM_DEBUG" + fi + + if [ "$enable_osx_g5" != "0" ]; then + CFLAGS="$CFLAGS -mcpu=G5 -mpowerpc64 -mtune=970 -mcpu=970 -mpowerpc-gpopt" + fi + + if [ -n "$personal_dir" ]; then + CFLAGS="$CFLAGS -DWITH_PERSONAL_DIR -DPERSONAL_DIR=\\\\\"$personal_dir\\\\\"" + fi + + if [ -n "$shared_dir" ]; then + CFLAGS="$CFLAGS -DWITH_SHARED_DIR -DSHARED_DIR=\\\\\"$shared_dir\\\\\"" + fi + + CFLAGS="$CFLAGS -DGLOBAL_DATA_DIR=\\\\\"$prefix_dir/$data_dir\\\\\"" + + if [ "$enable_lto" != "0" ]; then + lto_build=`echo "$FEATURES_BUILD" | grep "lto"` + lto_host=`echo "$FEATURES" | grep "lto"` + if [ -z "$lto_build$lto_host" ]; then + log 1 "WARNING: you enabled LTO/IPO, but neither build nor host compiler supports it" + log 1 "WARNING: LTO/IPO has been disabled" + fi + if [ -n "$lto_build" ]; then + LDFLAGS_BUILD="$LDFLAGS_BUILD $CFLAGS_BUILD $CXXFLAGS_BUILD" + fi + if [ -n "$lto_host" ]; then + LDFLAGS="$LDFLAGS $CFLAGS $CXXFLAGS" + fi + fi + + log 1 "using CFLAGS_BUILD... $CFLAGS_BUILD" + log 1 "using CXXFLAGS_BUILD... $CXXFLAGS_BUILD" + log 1 "using LDFLAGS_BUILD... $LDFLAGS_BUILD" + log 1 "using CFLAGS... $CFLAGS" + log 1 "using CXXFLAGS... $CXXFLAGS" + log 1 "using LDFLAGS... $LIBS $LDFLAGS" + + # Makedepend doesn't like something like: -isysroot /OSX/blabla + # so convert it to: -isysroot -OSX/blabla. makedepend just ignores + # any - command it doesn't know, so we are pretty save. + # Lovely hackish, not? + # Btw, this almost always comes from outside the configure, so it is + # not something we can control. + # Also make makedepend aware of compiler's built-in defines. + if [ "$with_makedepend" != "0" ] || [ "$enable_builtin_depend" != "0" ]; then + # Append CXXFLAGS possibly containing -std=c++0x + cflags_makedep="`echo | $cxx_host $CXXFLAGS -E -x c++ -dM - | sed 's@.define @-D@g;s@ .*@ @g;s@(.*)@@g' | tr -d '\r\n'`" + + # Please escape ALL " within ` because e.g. "" terminates the string in some sh implementations + cflags_makedep="$cflags_makedep `echo \"$CFLAGS\" \"$CXXFLAGS\" | sed 's@ /@ -@g;s@-I[ ]*[^ ]*@@g'`" + else + makedepend="" + fi + + if [ "$with_distcc" != "0" ]; then + cc_host="$distcc $cc_host" + cxx_host="$distcc $cxx_host" + log 1 "" + log 1 " NOTICE: remind yourself to use 'make -jN' to make use of distcc" + log 1 "" + fi + + if [ "$with_ccache" != "0" ]; then + cc_host="$ccache $cc_host" + cxx_host="$ccache $cxx_host" + fi +} + +check_compiler() { + # Params: + # $1 - Type for message (build / host) + # $2 - What to fill with the found compiler + # $3 - System to try + # $4 - Compiler to try + # $5 - Env-setting to try + # $6 - GCC alike to try + # $7 - CC alike to try + # $8 - "0" gcc, "1" g++, "2" windres, "3" strip, "4" lipo + # $9 - What the command is to check for + + if [ -n "$3" ]; then + # Check for system + if [ -z "$6" ]; then + compiler="$3" + else + compiler="$3-$6" + fi + machine=`eval $compiler $9 2>/dev/null` + ret=$? + eval "$2=\"$compiler\"" + + log 2 "executing $compiler $9" + log 2 " returned $machine" + log 2 " exit code $ret" + + if ( [ -z "$machine" ] && [ "$8" != "3" ] ) || [ "$ret" != "0" ]; then + log 1 "checking $1... $compiler not found" + log 1 "I couldn't detect any $6 binary for $3" + exit 1 + fi + + if [ "$machine" != "$3" ] && ( [ "$8" = "0" ] || [ "$8" = "1" ] ); then + log 1 "checking $1... expected $3, found $machine" + log 1 "the compiler suggests it doesn't build code for the machine you specified" + exit 1 + fi + elif [ -n "$4" ]; then + # Check for manual compiler + machine=`$4 $9 2>/dev/null` + ret=$? + eval "$2=\"$4\"" + + log 2 "executing $4 $9" + log 2 " returned $machine" + log 2 " exit code $ret" + + if ( [ -z "$machine" ] && [ "$8" != "3" ] ) || [ "$ret" != "0" ]; then + log 1 "checking $1... $4 not found" + log 1 "the selected binary doesn't seem to be a $6 binary" + exit 1 + fi + else + # Nothing given, autodetect + + if [ -n "$5" ]; then + machine=`$5 $9 2>/dev/null` + ret=$? + eval "$2=\"$5\"" + + log 2 "executing $5 $9" + log 2 " returned $machine" + log 2 " exit code $ret" + + # The user defined a GCC that doesn't reply to $9.. abort + if ( [ -z "$machine" ] && [ "$8" != "3" ] ) || [ "$ret" != "0" ]; then + log 1 "checking $1... $5 unusable" + log 1 "the CC environment variable is set, but it doesn't seem to be a $6 binary" + log 1 "please redefine the CC/CXX environment to a $6 binary" + exit 1 + fi + else + log 2 "checking $1... CC/CXX not set (skipping)" + + # No $5, so try '$6' + machine=`$6 $9 2>/dev/null` + ret=$? + eval "$2=\"$6\"" + + log 2 "executing $6 $9" + log 2 " returned $machine" + log 2 " exit code $ret" + + if ( [ -z "$machine" ] && [ "$8" != "3" ] ) || [ "$ret" != "0" ]; then + # Maybe '$7'? + machine=`$7 $9 2>/dev/null` + ret=$? + eval "$2=\"$7\"" + + log 2 "executing $7 $9" + log 2 " returned $machine" + log 2 " exit code $ret" + + # All failed, abort + if [ -z "$machine" ]; then + log 1 "checking $1... $6 not found" + log 1 "I couldn't detect any $6 binary on your system" + log 1 "please define the CC/CXX environment to where it is located" + + exit 1 + fi + fi + fi + fi + + if [ "$8" != "0" ]; then + eval "res=\$$2" + log 1 "checking $1... $res" + else + log 1 "checking $1... $machine" + fi +} + +check_build() { + if [ "$os" = "FREEBSD" ]; then + # FreeBSD's C compiler does not support dump machine. + # However, removing C support is not possible because PSP must be linked with the C compiler. + check_compiler "build system type" "cc_build" "$build" "$cc_build" "$CXX" "g++" "c++" "0" "-dumpmachine" + else + check_compiler "build system type" "cc_build" "$build" "$cc_build" "$CC" "gcc" "cc" "0" "-dumpmachine" + fi +} + +check_host() { + # By default the host is the build + if [ -z "$host" ]; then host="$build"; fi + + if [ "$os" = "FREEBSD" ]; then + # FreeBSD's C compiler does not support dump machine. + # However, removing C support is not possible because PSP must be linked with the C compiler. + check_compiler "host system type" "cc_host" "$host" "$cc_host" "$CXX" "g++" "c++" "0" "-dumpmachine" + else + check_compiler "host system type" "cc_host" "$host" "$cc_host" "$CC" "gcc" "cc" "0" "-dumpmachine" + fi +} + +check_cxx_build() { + check_compiler "build c++" "cxx_build" "$build" "$cxx_build" "$CXX" "g++" "c++" 1 "-dumpmachine" +} + +check_cxx_host() { + # By default the host is the build + if [ -z "$host" ]; then host="$build"; fi + check_compiler "host c++" "cxx_host" "$host" "$cxx_host" "$CXX" "g++" "c++" 1 "-dumpmachine" +} + +check_windres() { + if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "WINCE" ]; then + check_compiler "host windres" "windres" "$host" "$windres" "$WINDRES" "windres" "windres" "2" "-V" + fi +} + +check_strip() { + if [ "$os" = "OS2" ]; then + # OS2 via gcc is a bit weird.. stripping HAS to be done via emxbind, which is via gcc directly + log 1 "checking host strip... using gcc -s option" + elif [ "$os" = "OSX" ]; then + # Most targets have -V in strip, to see if they exists... OSX doesn't.. so execute something + echo "int main(int argc, char *argv[]) { }" > strip.test.c + $cxx_host strip.test.c -o strip.test + check_compiler "host strip" "strip" "$host" "$strip" "$STRIP" "strip" "strip" "3" "strip.test" + rm -f strip.test.c strip.test + else + check_compiler "host strip" "strip" "$host" "$strip" "$STRIP" "strip" "strip" "3" "-V" + fi +} + +check_lipo() { + if [ "$os" = "OSX" ] && [ "$enable_universal" != "0" ]; then + echo "int main(int argc, char *argv[]) { }" > lipo.test.c + $cxx_host lipo.test.c -o lipo.test + check_compiler "host lipo" "lipo" "$host" "$lipo" "$LIPO" "lipo" "lipo" "4" "-info lipo.test" + rm -f lipo.test.c lipo.test + fi +} + +check_osx_sdk() { + local sysroot="" + if [ -n "$1" ]; then + if echo "$1" | grep -q / ; then + # Seems to be a file system path + osx_sdk_path="$1" + else + osx_sdk_path="/Developer/SDKs/MacOSX$1.sdk" + fi + if [ ! -d "$osx_sdk_path" ]; then + # No directory, not present or garbage + return 1 + fi + + # Set minimum version to 10.4 as that's when kCGBitmapByteOrder32Host was introduced + sysroot="-isysroot $osx_sdk_path -Wl,-syslibroot,$osx_sdk_path -mmacosx-version-min=10.4" + fi + +cat > tmp.osx.mm << EOF +#include +int main() { + kCGBitmapByteOrder32Host; + return 0; +} +EOF + execute="$cxx_host $sysroot $CFLAGS tmp.osx.mm -framework Cocoa -o tmp.osx 2>&1" + eval $execute > /dev/null + ret=$? + log 2 "executing $execute" + log 2 " exit code $ret" + rm -f tmp.osx.mm tmp.osx + return $ret +} + +check_direct_music() { + echo " + #include + #include + #include + #include + #include + int main(int argc, char *argv[]) { }" > direct_music.test.c + $cxx_host $CFLAGS direct_music.test.c -o direct_music.test 2> /dev/null + res=$? + rm -f direct_music.test.c direct_music.test + + if [ "$res" != "0" ]; then + if [ "$with_direct_music" != "1" ]; then + log 1 "configure: error: direct-music is not available on this system" + exit 1 + fi + with_direct_music="0" + + log 1 "checking direct-music... not found" + else + log 1 "checking direct-music... found" + fi +} + +check_makedepend() { + if [ "$enable_builtin_depend" != "0" ]; then + with_makedepend="0" + fi + + if [ "$with_makedepend" = "0" ]; then + log 1 "checking makedepend... disabled" + return + fi + + if [ "$with_makedepend" = "1" ] || [ "$with_makedepend" = "2" ]; then + makedepend="makedepend" + else + makedepend="$with_makedepend" + fi + + rm -f makedepend.tmp + touch makedepend.tmp + res=`$makedepend -fmakedepend.tmp 2>/dev/null` + res=$? + log 2 "executing $makedepend -f makedepend.tmp" + log 2 " returned `cat makedepend.tmp`" + log 2 " exit code $ret" + + if [ ! -s makedepend.tmp ]; then + rm -f makedepend.tmp makedepend.tmp.bak + + if [ "$with_makedepend" = "2" ]; then + log 1 "checking makedepend... not found" + + log 1 "I couldn't detect any makedepend on your system" + log 1 "please locate it via --makedepend=[binary]" + + exit 1 + elif [ "$with_makedepend" != "1" ]; then + log 1 "checking makedepend... $makedepend not found" + + log 1 "the selected file doesn't seem to be a valid makedepend binary" + + exit 1 + else + log 1 "checking makedepend... not found" + + with_makedepend="0" + return + fi + fi + + rm -f makedepend.tmp makedepend.tmp.bak + + log 1 "checking makedepend... $makedepend" +} + +check_version() { + # $1 - requested version (major.minor) + # $2 - version we got (major.minor) + + if [ -z "$2" ]; then + return 0 + fi + + req_major=`echo $1 | cut -d. -f1` + got_major=`echo $2 | cut -d. -f1` + if [ $got_major -lt $req_major ]; then + return 0 + elif [ $got_major -gt $req_major ]; then + return 1 + fi + + req_minor=`echo $1 | cut -d. -f2` + got_minor=`echo $2 | cut -d. -f2` + if [ $got_minor -lt $req_minor ]; then + return 0 + fi + return 1 +} + +detect_awk() { + # Not all awks allow gsub(), so we test for that here! It is in fact all we need... + + # These awks are known to work. Test for them explicit + awks="gawk mawk nawk" + + awk_prefix="echo \"a.c b.c c.c\" | tr ' ' \\\\n | " + awk_param="' { ORS = \" \" } /\.c$/ { gsub(\".c$\", \".o\", \$0); print \$0; }' 2>/dev/null" + awk_result="a.o b.o c.o " + log 2 "Detecing awk..." + + log 2 "Trying: $awk_prefix $awk $awk_param" + res=`eval $awk_prefix $awk $awk_param` + log 2 "Result: '$res'" + if [ "$res" != "$awk_result" ] && [ "$awk" = "awk" ]; then + # User didn't supply his own awk, so try to detect some other known working names for an awk + for awk in $awks; do + log 2 "Trying: $awk_prefix $awk $awk_param" + res=`eval $awk_prefix $awk $awk_param` + log 2 "Result: '$res'" + if [ "$res" = "$awk_result" ]; then break; fi + done + + if [ "$res" != "$awk_result" ]; then + log 1 "checking awk... not found" + log 1 "configure: error: no awk found" + log 1 "configure: error: please install one of the following: $awks" + exit 1 + fi + fi + if [ "$res" != "$awk_result" ]; then + log 1 "checking awk... not found" + log 1 "configure: error: you supplied '$awk' but it doesn't seem a valid gawk or mawk" + exit 1 + fi + + log 1 "checking awk... $awk" +} + +detect_os() { + if [ "$os" = "DETECT" ]; then + # Detect UNIX, OSX, FREEBSD, DRAGONFLY, OPENBSD, NETBSD, HPUX, MORPHOS, BEOS, SUNOS, CYGWIN, MINGW, OS2, DOS, WINCE, and PSP + + # Try first via dumpmachine, then via uname + os=`echo "$host" | tr '[A-Z]' '[a-z]' | $awk ' + /linux/ { print "UNIX"; exit} + /darwin/ { print "OSX"; exit} + /freebsd/ { print "FREEBSD"; exit} + /dragonfly/ { print "DRAGONFLY"; exit} + /openbsd/ { print "OPENBSD"; exit} + /netbsd/ { print "NETBSD"; exit} + /hp-ux/ { print "HPUX"; exit} + /morphos/ { print "MORPHOS"; exit} + /beos/ { print "BEOS"; exit} + /haiku/ { print "HAIKU"; exit} + /sunos/ { print "SUNOS"; exit} + /solaris/ { print "SUNOS"; exit} + /cygwin/ { print "CYGWIN"; exit} + /mingw/ { print "MINGW"; exit} + /os2/ { print "OS2"; exit} + /dos/ { print "DOS"; exit} + /wince/ { print "WINCE"; exit} + /psp/ { print "PSP"; exit} + '` + + if [ -z "$os" ]; then + os=`LC_ALL=C uname | tr '[A-Z]' '[a-z]' | $awk ' + /linux/ { print "UNIX"; exit} + /darwin/ { print "OSX"; exit} + /freebsd/ { print "FREEBSD"; exit} + /dragonfly/ { print "DRAGONFLY"; exit} + /openbsd/ { print "OPENBSD"; exit} + /netbsd/ { print "NETBSD"; exit} + /hp-ux/ { print "HPUX"; exit} + /morphos/ { print "MORPHOS"; exit} + /beos/ { print "BEOS"; exit} + /haiku/ { print "HAIKU"; exit} + /sunos/ { print "SUNOS"; exit} + /cygwin/ { print "CYGWIN"; exit} + /mingw/ { print "MINGW"; exit} + /os\/2/ { print "OS2"; exit} + /gnu/ { print "UNIX"; exit} + '` + fi + + if [ -z "$os" ]; then + log 1 "detecting OS... none detected" + log 1 "I couldn't detect your OS. Please use --os=OS to force one" + log 1 "Allowed values are: UNIX, OSX, FREEBSD, DRAGONFLY, OPENBSD, NETBSD, MORPHOS, HPUX, BEOS, HAIKU, SUNOS, CYGWIN, MINGW, OS2, DOS, WINCE, and PSP" + exit 1 + fi + + log 1 "detecting OS... $os" + else + log 1 "forcing OS... $os" + fi +} + +detect_allegro() { + # 0 means no, 1 is auto-detect, 2 is force + if [ "$with_allegro" = "0" ]; then + log 1 "checking Allegro... disabled" + + allegro_config="" + return 0 + fi + + if [ "$with_allegro" = "2" ] && [ "$with_cocoa" = "2" ]; then + log 1 "configure: error: it is impossible to compile both Allegro and COCOA" + log 1 "configure: error: please deselect one of them and try again" + exit 1 + fi + + if [ "$with_allegro" = "2" ] && [ "$enable_dedicated" != "0" ]; then + log 1 "configure: error: it is impossible to compile a dedicated with Allegro" + log 1 "configure: error: please deselect one of them and try again" + exit 1 + fi + + if [ "$enable_dedicated" != "0" ]; then + log 1 "checking Allegro... dedicated server, skipping" + + allegro_config="" + return 0 + fi + + # By default on OSX we don't use SDL. The rest is auto-detect + if [ "$with_allegro" = "1" ] && [ "$os" = "OSX" ] && [ "$with_cocoa" != "0" ]; then + log 1 "checking Allegro... OSX, skipping" + + allegro_config="" + return 0 + fi + + if [ "$with_allegro" = "1" ] || [ "$with_allegro" = "" ] || [ "$with_allegro" = "2" ]; then + allegro_config="allegro-config" + else + allegro_config="$with_allegro" + fi + + version=`$allegro_config --version 2>/dev/null` + ret=$? + log 2 "executing $allegro_config --version" + log 2 " returned $version" + log 2 " exit code $ret" + + if [ -z "$version" ] || [ "$ret" != "0" ]; then + log 1 "checking Allegro... not found" + + # It was forced, so it should be found. + if [ "$with_allegro" != "1" ]; then + log 1 "configure: error: allegro-config couldn't be found" + log 1 "configure: error: you supplied '$with_allegro', but it seems invalid" + exit 1 + fi + + allegro_config="" + return 0 + fi + + log 1 "checking Allegro... found" +} + + +detect_sdl() { + # 0 means no, 1 is auto-detect, 2 is force + if [ "$with_sdl" = "0" ]; then + log 1 "checking SDL... disabled" + + sdl_config="" + return 0 + fi + + if [ "$with_sdl" = "2" ] && [ "$with_cocoa" = "2" ]; then + log 1 "configure: error: it is impossible to compile both SDL and COCOA" + log 1 "configure: error: please deselect one of them and try again" + exit 1 + fi + + if [ "$with_sdl" = "2" ] && [ "$enable_dedicated" != "0" ]; then + log 1 "configure: error: it is impossible to compile a dedicated with SDL" + log 1 "configure: error: please deselect one of them and try again" + exit 1 + fi + + if [ "$enable_dedicated" != "0" ]; then + log 1 "checking SDL... dedicated server, skipping" + + sdl_config="" + return 0 + fi + + # By default on OSX we don't use SDL. The rest is auto-detect + if [ "$with_sdl" = "1" ] && [ "$os" = "OSX" ] && [ "$with_cocoa" != "0" ]; then + log 1 "checking SDL... OSX, skipping" + + sdl_config="" + return 0 + fi + + if [ "$os" = "OSX" ]; then + log 1 "WARNING: sdl is known to fail on some versions of Mac OS X" + log 1 "WARNING: with some hardware configurations. Use at own risk!" + sleep 5 + fi + + if [ "$with_sdl" = "1" ] || [ "$with_sdl" = "" ] || [ "$with_sdl" = "2" ]; then + sdl_config="sdl-config" + else + sdl_config="$with_sdl" + fi + + version=`$sdl_config --version 2>/dev/null` + ret=$? + log 2 "executing $sdl_config --version" + log 2 " returned $version" + log 2 " exit code $ret" + + if [ -z "$version" ] || [ "$ret" != "0" ]; then + log 1 "checking SDL... not found" + + # It was forced, so it should be found. + if [ "$with_sdl" != "1" ]; then + log 1 "configure: error: sdl-config couldn't be found" + log 1 "configure: error: you supplied '$with_sdl', but it seems invalid" + exit 1 + fi + + sdl_config="" + return 0 + fi + + log 1 "checking SDL... found" +} + +detect_osx_sdk() { + # Try to find the best SDK available. For a normal build this + # is currently the 10.5 SDK as this is needed to compile all + # optional code. Because such an executable won't run on 10.4 + # or lower, also check for the 10.4u SDK when doing an universal + # build. + + # Check for the 10.5 SDK, but try 10.6 if that fails + check_osx_sdk "10.5" || check_osx_sdk "10.6" || osx_sdk_path="" + + if [ -z "$osx_sdk_path" ] || [ "$enable_universal" != "0" ]; then + # No better SDK or universal build enabled? Check 10.4u SDK as well + local old_sdk="$osx_sdk_path" + if check_osx_sdk "10.4u"; then + osx_sdk_104_path="$osx_sdk_path" + else + osx_sdk_104_path="" + fi + if [ -z "$old_sdk" ]; then + osx_sdk_path="$osx_sdk_104_path" + else + osx_sdk_path="$old_sdk" + fi + fi + + if [ -z "$osx_sdk_path" ]; then + log 1 "Your system SDK is probably too old" + log 1 "Please install/upgrade your Xcode to >= 2.5" + + exit 1 + fi +} + +detect_cocoa() { + # 0 means no, 1 is auto-detect, 2 is force + if [ "$with_cocoa" = "0" ]; then + log 1 "checking COCOA... disabled" + + return 0 + fi + + if [ "$with_cocoa" = "2" ] && [ "$enable_dedicated" != "0" ]; then + log 1 "configure: error: it is impossible to compile a dedicated with COCOA" + log 1 "configure: error: please deselect one of them and try again" + exit 1 + fi + + if [ "$enable_dedicated" != "0" ]; then + log 1 "checking COCOA... dedicated server, skipping" + + with_cocoa="0" + return 0 + fi + + # By default on OSX we use COCOA. The rest doesn't support it + if [ "$with_cocoa" = "1" ] && [ "$os" != "OSX" ]; then + log 1 "checking COCOA... not OSX, skipping" + + with_cocoa="0" + return 0 + fi + + if [ "$os" != "OSX" ]; then + log 1 "checking COCOA... not OSX" + + log 1 "configure: error: COCOA video driver is only supported for OSX" + exit 1 + fi + + log 1 "checking COCOA... found" + + + if [ "$enable_cocoa_quartz" != "0" ]; then + log 1 "checking whether to enable the Quartz window subdriver... yes" + else + log 1 "checking whether to enable the Quartz window subdriver... no" + fi + + detect_quickdraw +} + +detect_quickdraw() { + # 0 means no, 1 is auto-detect, 2 is force + if [ "$enable_cocoa_quickdraw" = "0" ]; then + log 1 "checking Quickdraw window subdriver... disabled" + return 0 + fi + + # Assume QuickDraw is available when doing an universal build + if [ "$enable_universal" != "0" ]; then + log 1 "checking Quickdraw window subdriver... found" + return 0 + fi + + # 64 bits doesn't have quickdraw + if [ "$cpu_type" = "64" ]; then + enable_cocoa_quickdraw="0" + log 1 "checking Quickdraw window subdriver... disabled (64 bits)" + return 0 + fi + +cat > tmp.osx.mm << EOF +#include +#import +int main(int argc, char *argv[]) { SetEmptyRgn(NULL); return 0; } +EOF + execute="$cxx_host $OSX_SYSROOT $OSX_LD_SYSROOT $CFLAGS -mmacosx-version-min=10.3 tmp.osx.mm -framework Cocoa -o tmp.osx 2>&1" + eval $execute > /dev/null + ret=$? + log 2 "executing $execute" + log 2 " exit code $ret" + rm -f tmp.osx.mm tmp.osx + if [ "$ret" != "0" ]; then + log 1 "checking Quickdraw window subdriver... not found" + + # It was forced, so it should be found. + if [ "$enable_cocoa_quickdraw" != "1" ]; then + log 1 "configure: error: Quickdraw window driver could not be found" + exit 1 + fi + + enable_cocoa_quickdraw=0 + return 0 + fi + + enable_cocoa_quickdraw=1 + log 1 "checking Quickdraw window subdriver... found" +} + +detect_library() { + # $1 - config-param ($with_zlib value) + # $2 - library name ('zlib', sets $zlib) + # $3 - static library name (libz.a) + # $4 - header directory () + # $5 - header name (zlib.h) + # $6 - force static (if non-empty) + + if [ -n "$6" ]; then force_static="1"; fi + + # 0 means no, 1 is auto-detect, 2 is force + if [ "$1" = "0" ]; then + log 1 "checking $2... disabled" + + eval "$2=\"\"" + return 0 + fi + + log 2 "detecting $2" + + if [ "$1" = "1" ] || [ "$1" = "" ] || [ "$1" = "2" ]; then + eval "$2=`ls -1 /usr/include/$4*.h 2>/dev/null | egrep \"\/$5\$\"`" + eval "res=\$$2" + if [ -z "$res" ]; then + log 2 " trying /usr/include/$4$5... no" + eval "$2=`ls -1 /usr/local/include/$4*.h 2>/dev/null | egrep \"\/$5\$\"`" + fi + eval "res=\$$2" + if [ -z "$res" ]; then + log 2 " trying /usr/local/include/$4$5... no" + eval "$2=`ls -1 /mingw/include/$4*.h 2>/dev/null | egrep \"\/$5\$\"`" + fi + eval "res=\$$2" + if [ -z "$res" ]; then + log 2 " trying /mingw/include/$4$5... no" + eval "$2=`ls -1 /opt/local/include/$4*.h 2>/dev/null | egrep \"\/$5\$\"`" + fi + eval "res=\$$2" + if [ -z "$res" ]; then + log 2 " trying /opt/local/include/$4$5... no" + fi + if [ -z "$res" ] && [ "$os" = "NETBSD" ]; then + eval "$2=`ls -1 /usr/pkg/include/$4*.h 2>/dev/null | egrep \"\/$5\$\"`" + eval "res=\$$2" + if [ -z "$res" ]; then + log 2 " trying /usr/pkg/include/$4$5... no" + fi + fi + if [ -z "$res" ] && [ "$os" = "HAIKU" ]; then + eval "$2=`ls -1 /boot/common/include/$4*.h 2>/dev/null | egrep \"\/$5\$\"`" + eval "res=\$$2" + if [ -z "$res" ]; then + log 2 " trying /boot/common/include/$4$5... no" + fi + fi + + eval "res=\$$2" + if [ -n "$res" ] && ( [ -n "$force_static" ] || ( [ "$enable_static" != "0" ] && [ "$os" != "OSX" ] ) ); then + eval "res=\$$2" + log 2 " trying $res... found" + # Now find the static lib, if needed + eval "$2=`ls /lib/*.a 2>/dev/null | egrep \"\/$3\$\"`" + eval "res=\$$2" + if [ -z "$res" ]; then + log 2 " trying /lib/$3... no" + eval "$2=`ls /usr/lib/*.a 2>/dev/null | egrep \"\/$3\$\"`" + fi + eval "res=\$$2" + if [ -z "$res" ]; then + log 2 " trying /usr/lib/$3... no" + eval "$2=`ls /usr/local/lib/*.a 2>/dev/null | egrep \"\/$3\$\"`" + fi + eval "res=\$$2" + if [ -z "$res" ]; then + log 2 " trying /usr/local/lib/$3... no" + eval "$2=`ls /mingw/lib/*.a 2>/dev/null | egrep \"\/$3\$\"`" + fi + eval "res=\$$2" + if [ -z "$res" ]; then + log 2 " trying /mingw/lib/$3... no" + log 1 "configure: error: $2 couldn't be found" + log 1 "configure: error: you requested a static link, but I can't find $3" + + exit 1 + fi + fi + else + # Make sure it exists + if [ -f "$1" ]; then + eval "$2=`ls $1 2>/dev/null`" + else + eval "$2=`ls $1/$3 2>/dev/null`" + fi + fi + + eval "res=\$$2" + if [ -z "$res" ]; then + log 1 "checking $2... not found" + if [ "$1" = "2" ]; then + log 1 "configure: error: $2 couldn't be found" + + exit 1 + elif [ "$1" != "1" ]; then + log 1 "configure: error: $2 couldn't be found" + log 1 "configure: error: you supplied '$1', but it seems invalid" + + exit 1 + fi + + eval "with_$2=0" + + return 0 + fi + + eval "res=\$$2" + log 2 " trying $res... found" + + log 1 "checking $2... found" +} + +detect_zlib() { + detect_library "$with_zlib" "zlib" "libz.a" "" "zlib.h" +} + +detect_lzo2() { + detect_library "$with_lzo2" "lzo2" "liblzo2.a" "lzo/" "lzo1x.h" +} + +detect_libtimidity() { + detect_library "$with_libtimidity" "libtimidity" "libtimidity.a" "" "timidity.h" +} + +detect_pkg_config() { + # $1 - config-param ($with_lzma value) + # $2 - package name ('liblzma') + # $3 - config name ('lzma_config', sets $lzma_config) + # $4 - minimum module version ('2.3') + + # 0 means no, 1 is auto-detect, 2 is force + if [ "$1" = "0" ]; then + log 1 "checking $2... disabled" + + eval "$3=\"\"" + return 0 + fi + + log 2 "detecting $2" + + if [ "$1" = "1" ] || [ "$1" = "" ] || [ "$1" = "2" ]; then + pkg_config_call="pkg-config $2" + else + pkg_config_call="$1" + fi + + version=`$pkg_config_call --modversion 2>/dev/null` + ret=$? + check_version "$4" "$version" + version_ok=$? + log 2 "executing $pkg_config_call --modversion" + log 2 " returned $version" + log 2 " exit code $ret" + + if [ -z "$version" ] || [ "$ret" != "0" ] || [ "$version_ok" != "1" ]; then + if [ -n "$version" ] && [ "$version_ok" != "1" ]; then + log 1 "checking $2... needs at least version $4, $2 NOT enabled" + else + log 1 "checking $2... not found" + fi + + # It was forced, so it should be found. + if [ "$1" != "1" ]; then + log 1 "configure: error: pkg-config $2 couldn't be found" + log 1 "configure: error: you supplied '$1', but it seems invalid" + exit 1 + fi + + eval "$3=\"\"" + return 0 + fi + + eval "$3=\"$pkg_config_call\"" + log 1 "checking $2... found" +} + +detect_lzma() { + detect_pkg_config "$with_lzma" "liblzma" "lzma_config" "5.0" +} + +detect_xdg_basedir() { + detect_pkg_config "$with_xdg_basedir" "libxdg-basedir" "xdg_basedir_config" "1.2" +} + +detect_png() { + # 0 means no, 1 is auto-detect, 2 is force + if [ "$with_png" = "0" ]; then + log 1 "checking libpng... disabled" + + png_config="" + return 0 + fi + + if [ "$with_zlib" = "0" ] || [ -z "$zlib" ]; then + if [ "$with_png" != "1" ]; then + log 1 "checking libpng... no zlib" + log 1 "ERROR: libpng was forced, but zlib was not detected / disabled." + log 1 "ERROR: libpng depends on zlib." + + exit 1 + fi + + log 1 "checking libpng... no zlib, skipping" + + png_config="" + return 0 + fi + + detect_pkg_config "$with_png" "libpng" "png_config" "1.2" +} + +detect_freetype() { + # 0 means no, 1 is auto-detect, 2 is force + if [ "$with_freetype" = "0" ]; then + log 1 "checking libfreetype... disabled" + + freetype_config="" + return 0 + fi + if [ "$with_freetype" = "1" ] && [ "$enable_dedicated" != "0" ]; then + log 1 "checking libfreetype... dedicated server, skipping" + + freetype_config="" + return 0 + fi + + if [ "$with_zlib" = "0" ] || [ -z "$zlib" ]; then + if [ "$with_freetype" != "1" ]; then + log 1 "checking libfreetype... no zlib" + log 1 "ERROR: libfreetype was forced, but zlib was not detected / disabled." + log 1 "ERROR: libfreetype depends on zlib." + + exit 1 + fi + + log 1 "checking libfreetype... no zlib, skipping" + + freetype_config="" + return 0 + fi + + if [ "$with_freetype" = "1" ] || [ "$with_freetype" = "" ] || [ "$with_freetype" = "2" ]; then + freetype_config="freetype-config" + else + freetype_config="$with_freetype" + fi + + version=`$freetype_config --version 2>/dev/null` + ret=$? + log 2 "executing freetype_config --version" + log 2 " returned $version" + log 2 " exit code $ret" + + if [ -z "$version" ] || [ "$ret" != "0" ]; then + log 1 "checking libfreetype... not found" + + # It was forced, so it should be found. + if [ "$with_freetype" != "1" ]; then + log 1 "configure: error: freetype-config couldn't be found" + log 1 "configure: error: you supplied '$with_freetype', but it seems invalid" + exit 1 + fi + + freetype_config="" + return 0 + fi + + log 1 "checking libfreetype... found" +} + +detect_fontconfig() { + # 0 means no, 1 is auto-detect, 2 is force + if [ "$with_fontconfig" = "0" ]; then + log 1 "checking libfontconfig... disabled" + + fontconfig_config="" + return 0 + fi + if [ "$with_fontconfig" = "1" ] && [ "$enable_dedicated" != "0" ]; then + log 1 "checking libfontconfig... dedicated server, skipping" + + fontconfig_config="" + return 0 + fi + if [ "$with_fontconfig" != "2" ] && [ -z "$freetype_config" ]; then + log 1 "checking libfontconfig... no freetype, skipping" + + fontconfig_config="" + return 0 + fi + + if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "WINCE" ]; then + log 1 "checking libfontconfig... WIN32, skipping" + fontconfig_config="" + return 0 + fi + + if [ "$os" = "OSX" ]; then + log 1 "checking libfontconfig... OSX, skipping" + fontconfig_config="" + return 0 + fi + + detect_pkg_config "$with_fontconfig" "fontconfig" "fontconfig_config" "2.3" +} + +detect_icu() { + # 0 means no, 1 is auto-detect, 2 is force + if [ "$with_icu" = "0" ]; then + log 1 "checking libicu... disabled" + + icu_config="" + return 0 + fi + if [ "$with_icu" = "1" ] && [ "$enable_dedicated" != "0" ]; then + log 1 "checking libicu... dedicated server, skipping" + + icu_config="" + return 0 + fi + + if [ "$with_icu" = "1" ] || [ "$with_icu" = "" ] || [ "$with_icu" = "2" ]; then + icu_config="icu-config" + else + icu_config="$with_icu" + fi + + version=`$icu_config --version 2>/dev/null` + ret=$? + check_version '3.6' "$version" + version_ok=$? + log 2 "executing $icu_config --version" + log 2 " returned $version" + log 2 " exit code $ret" + + if [ -z "$version" ] || [ "$ret" != "0" ] || [ "$version_ok" != "1" ]; then + if [ -n "$version" ] && [ "$version_ok" != "1" ]; then + log 1 "checking libicu... needs at least version 3.6.0, icu NOT enabled" + else + log 1 "checking libicu... not found" + fi + + # It was forced, so it should be found. + if [ "$with_icu" != "1" ]; then + log 1 "configure: error: icu-config couldn't be found" + log 1 "configure: error: you supplied '$with_icu', but it seems invalid" + exit 1 + fi + + icu_config="" + return 0 + fi + + log 1 "checking libicu... found" +} + +detect_pspconfig() { + # 0 means no, 1 is auto-detect, 2 is force + if [ "$with_psp_config" = "0" ]; then + log 1 "checking psp-config... disabled" + + psp_config="" + return 0 + fi + + if [ "$with_psp_config" = "1" ] && [ "$os" != "PSP" ]; then + log 1 "checking psp-config... not PSP, skipping" + + psp_config=""; + return 0 + fi + + if [ "$os" != "PSP" ]; then + log 1 "checking psp-config... not PSP" + + log 1 "configure: error: psp-config is only supported for PSP" + exit 1 + fi + + if [ "$with_psp_config" = "1" ] || [ "$with_psp_config" = "" ] || [ "$with_psp_config" = "2" ]; then + psp_config="psp-config" + else + psp_config="$with_psp_config" + fi + + version=`$psp_config -p 2>/dev/null` + ret=$? + log 2 "executing $psp_config -p" + log 2 " returned $version" + log 2 " exit code $ret" + + if [ -z "$version" ] || [ "$ret" != "0" ]; then + log 1 "checking psp-config... not found" + log 1 "configure: error: psp-config couldn't be found" + + # It was forced, so it should be found. + if [ "$with_psp_config" != "1" ]; then + log 1 "configure: error: you supplied '$with_psp_config', but it seems invalid" + fi + exit 1 + fi + + log 1 "checking psp-config... found" +} + +detect_iconv() { + # 0 means no, 1 is auto-detect, 2 is force + if [ "$with_iconv" = "0" ]; then + log 1 "checking iconv... disabled" + + return 0 + fi + + if [ "$with_iconv" = "1" ] && [ "$os" != "OSX" ]; then + log 1 "checking iconv... not OSX, skipping" + with_iconv="0" + + return 0 + fi + + # Try to find iconv.h, seems to only thing to detect iconv with + + if [ "$with_iconv" = "1" ] || [ "$with_iconv" = "" ] || [ "$with_iconv" = "2" ]; then + iconv=`ls -1 /usr/include 2>/dev/null | grep "iconv.h"` + if [ -z "$iconv" ]; then + iconv=`ls -1 /usr/local/include 2>/dev/null | grep "iconv.h"` + fi + else + # Make sure it exists + iconv=`ls $with_iconv/include/iconv.h 2>/dev/null` + fi + + if [ -z "$iconv" ]; then + log 1 "checking iconv... not found" + if [ "$with_iconv" = "2" ]; then + log 1 "configure: error: iconv couldn't be found" + + exit 1 + elif [ "$with_iconv" != "1" ]; then + log 1 "configure: error: iconv couldn't be found" + log 1 "configure: error: you supplied '$with_iconv', but I couldn't detect iconv in it" + + exit 1 + fi + + return 0 + fi + + if [ "$with_iconv" = "1" ]; then + with_iconv="2" + fi + + log 2 "found iconv in $iconv" + + log 1 "checking iconv... found" + + # There are different implementations of iconv. The older ones, + # e.g. SUSv2, pass a const pointer, whereas the newer ones, e.g. + # IEEE 1003.1 (2004), pass a non-const pointer. + + cat > tmp.iconv.cpp << EOF +#include "src/stdafx.h" +#include +int main() { + static char buf[1024]; + iconv_t convd = 0; + const char *inbuf = ""; + char *outbuf = buf; + size_t outlen = 1023; + size_t inlen = 0; + return iconv(convd, &inbuf, &inlen, &outbuf, &outlen); +} +EOF + execute="$cxx_host $OSX_SYSROOT $CFLAGS -c tmp.iconv.cpp -o tmp.iconv -DTESTING 2>&1" + eval $execute > /dev/null + ret=$? + log 2 "executing $execute" + log 2 " exit code $ret" + if [ "$ret" = "0" ]; then have_non_const_iconv="no"; else have_non_const_iconv="yes"; fi + log 1 "checking if iconv has non-const inbuf... $have_non_const_iconv" + + cat > tmp.iconv.cpp << EOF +#include "src/stdafx.h" +#include +int main() { + static char buf[1024]; + iconv_t convd = 0; + char *inbuf = ""; + char *outbuf = buf; + size_t outlen = 1023; + size_t inlen = 0; + return iconv(convd, &inbuf, &inlen, &outbuf, &outlen); +} +EOF + execute="$cxx_host $OSX_SYSROOT $OSX_LD_SYSROOT $CFLAGS tmp.iconv.cpp -o tmp.iconv -DTESTING 2>&1" + eval $execute > /dev/null + ret=$? + log 2 "executing $execute" + log 2 " exit code $ret" + if [ "$ret" = "0" ]; then link_to_iconv="no"; else link_to_iconv="yes"; fi + log 1 "checking whether to link to iconv... $link_to_iconv" + rm -f tmp.iconv tmp.iconv.cpp +} + +_detect_sort() { + sort_test_in="d +a +c +b" + + sort_test_out="a +b +c +d" + + log 2 "running echo | $1" + + if [ "`echo \"$sort_test_in\" | $1 2>/dev/null`" = "$sort_test_out" ]; then + sort="$1" + log 2 " result was valid" + else + log 2 " result was invalid" + fi +} + +detect_sort() { + if [ "$with_sort" = "0" ]; then + log 1 "checking sort... disabled" + + return + fi + + if [ "$with_sort" = "1" ] || [ "$with_sort" = "2" ]; then + _detect_sort "sort" + if [ -z "$sort" ]; then _detect_sort "/sbin/sort"; fi + if [ -z "$sort" ]; then _detect_sort "/usr/sbin/sort"; fi + if [ -z "$sort" ]; then _detect_sort "/usr/local/sbin/sort"; fi + if [ -z "$sort" ]; then _detect_sort "/bin/sort"; fi + if [ -z "$sort" ]; then _detect_sort "/usr/bin/sort"; fi + if [ -z "$sort" ]; then _detect_sort "/usr/local/bin/sort"; fi + else + _detect_sort "$with_sort" + fi + + if [ -z "$sort" ]; then + if [ "$with_sort" = "2" ]; then + log 1 "checking sort... not found" + + log 1 "configure: error: couldn't detect sort on your system" + exit 1 + elif [ "$with_sort" != "1" ]; then + log 1 "checking sort... $with_sort not found" + + log 1 "configure: error: '$with_sort' doesn't look like a sort to me" + log 1 "configure: error: please verify its location and function and try again" + + exit 1 + else + log 1 "checking sort... not found" + fi + else + log 1 "checking sort... $sort" + fi +} + +detect_grfcodec() { + # 0 means no, 1 is auto-detect, 2 is force + if [ "$with_grfcodec" = "0" ]; then + log 1 "checking grfcodec... disabled" + + grfcodec="" + return 0 + fi + + if [ "$with_grfcodec" = "1" ] || [ "$with_grfcodec" = "" ] || [ "$with_grfcodec" = "2" ]; then + grfcodec="grfcodec" + else + grfcodec="$with_grfcodec" + fi + + version=`$grfcodec -v 2>/dev/null | $awk '{print $3}' | sed 's/[rM]//g;s/-/0/'` + ret=$? + log 2 "executing grfcodec -v" + log 2 " returned $version" + log 2 " exit code $ret" + + if [ -z "$version" ] || [ "$ret" != "0" ] || [ "$version" -lt "985" ]; then + if [ -n "$version" ] && [ "$version" -lt "985" ]; then + log 1 "checking grfcodec... needs at least version 6.0.5 (r985), disabled" + else + log 1 "checking grfcodec... not found" + fi + + # It was forced, so it should be found. + if [ "$with_grfcodec" != "1" ]; then + log 1 "configure: error: grfcodec couldn't be found" + log 1 "configure: error: you supplied '$with_grfcodec', but it seems invalid" + exit 1 + fi + + grfcodec="" + return 0 + fi + + log 1 "checking grfcodec... found" +} + +detect_nforenum() { + # 0 means no, 1 is auto-detect, 2 is force + if [ "$with_nforenum" = "0" ]; then + log 1 "checking nforenum... disabled" + + nforenum="" + return 0 + fi + + if [ "$with_nforenum" = "1" ] || [ "$with_nforenum" = "" ] || [ "$with_nforenum" = "2" ]; then + nforenum="nforenum" + else + nforenum="$with_nforenum" + fi + + version=`$nforenum -v 2>/dev/null | $awk '{print $3}' | sed 's/[rM]//g;s/-/0/'` + ret=$? + log 2 "executing nforenum -v" + log 2 " returned $version" + log 2 " exit code $ret" + + if [ -z "$version" ] || [ "$ret" != "0" ] || [ "$version" -lt "985" ]; then + if [ -n "$version" ] && [ "$version" -lt "985" ]; then + log 1 "checking nforenum... needs at least version 6.0.5 (r985), disabled" + else + log 1 "checking nforenum... not found" + fi + + # It was forced, so it should be found. + if [ "$with_nforenum" != "1" ]; then + log 1 "configure: error: nforenum couldn't be found" + log 1 "configure: error: you supplied '$with_nforenum', but it seems invalid" + exit 1 + fi + + nforenum="" + return 0 + fi + + log 1 "checking nforenum... found" +} + +detect_cputype() { + if [ -n "$cpu_type" ] && [ "$cpu_type" != "DETECT" ]; then + log 1 "forcing cpu-type... $cpu_type bits" + return; + fi + echo "#define _SQ64 1" > tmp.64bit.cpp + echo "#include \"src/stdafx.h\"" >> tmp.64bit.cpp + echo "assert_compile(sizeof(size_t) == 8);" >> tmp.64bit.cpp + echo "int main() { return 0; }" >> tmp.64bit.cpp + execute="$cxx_host $CFLAGS tmp.64bit.cpp -o tmp.64bit -DTESTING 2>&1" + cpu_type="`eval $execute 2>/dev/null`" + ret=$? + log 2 "executing $execute" + log 2 " returned $cpu_type" + log 2 " exit code $ret" + if [ "$ret" = "0" ]; then cpu_type="64"; else cpu_type="32"; fi + log 1 "detecting cpu-type... $cpu_type bits" + rm -f tmp.64bit tmp.64bit.cpp +} + +detect_sse_capable_architecture() { + # 0 means no, 1 is auto-detect, 2 is force + if [ "$with_sse" = "0" ]; then + log 1 "checking SSE... disabled" + return + fi + + echo "#define _SQ64 1" > tmp.sse.cpp + echo "#include " >> tmp.sse.cpp + echo "#include " >> tmp.sse.cpp + echo "#include " >> tmp.sse.cpp + echo "int main() { return 0; }" >> tmp.sse.cpp + execute="$cxx_host -msse4.1 $CFLAGS tmp.sse.cpp -o tmp.sse 2>&1" + sse="`eval $execute 2>/dev/null`" + ret=$? + log 2 "executing $execute" + log 2 " returned $sse" + log 2 " exit code $ret" + if [ "$ret" = "0" ]; then + log 1 "detecting SSE... found" + else + # It was forced, so it should be found. + if [ "$with_sse" != "1" ]; then + log 1 "configure: error: SSE couln't be found" + log 1 "configure: error: you force enabled SSE, but it seems unavailable" + exit 1 + fi + + log 1 "detecting SSE... not found" + with_sse="0" + fi + rm -f tmp.sse tmp.exe tmp.sse.cpp +} + +make_sed() { + T_CFLAGS="$CFLAGS" + T_CXXFLAGS="$CXXFLAGS" + T_LDFLAGS="$LDFLAGS" + + SRC_OBJS_DIR="$BASE_SRC_OBJS_DIR/$OBJS_SUBDIR" + + # All the data needed to compile a single target + # Make sure if you compile multiple targets to + # use multiple OBJS_DIR, because all in-between + # binaries are stored in there, and nowhere else. + SRC_REPLACE=" + s@!!CC_HOST!!@$cc_host@g; + s@!!CXX_HOST!!@$cxx_host@g; + s@!!CC_BUILD!!@$cc_build@g; + s@!!CXX_BUILD!!@$cxx_build@g; + s@!!WINDRES!!@$windres@g; + s@!!STRIP!!@$strip $strip_arg@g; + s@!!LIPO!!@$lipo@g; + s@!!CFLAGS!!@$T_CFLAGS@g; + s@!!CFLAGS_BUILD!!@$CFLAGS_BUILD@g; + s@!!CXXFLAGS!!@$T_CXXFLAGS@g; + s@!!CXXFLAGS_BUILD!!@$CXXFLAGS_BUILD@g; + s@!!STRGEN_FLAGS!!@$strgen_flags@g; + s@!!LIBS!!@$LIBS@g; + s@!!LDFLAGS!!@$T_LDFLAGS@g; + s@!!LDFLAGS_BUILD!!@$LDFLAGS_BUILD@g; + s@!!BIN_DIR!!@$BIN_DIR@g; + s@!!ROOT_DIR!!@$ROOT_DIR@g; + s@!!MEDIA_DIR!!@$MEDIA_DIR@g; + s@!!SOURCE_LIST!!@$SOURCE_LIST@g; + s@!!SRC_OBJS_DIR!!@$SRC_OBJS_DIR@g; + s@!!LANG_OBJS_DIR!!@$LANG_OBJS_DIR@g; + s@!!GRF_OBJS_DIR!!@$GRF_OBJS_DIR@g; + s@!!SETTING_OBJS_DIR!!@$SETTING_OBJS_DIR@g; + s@!!SRC_DIR!!@$SRC_DIR@g; + s@!!SCRIPT_SRC_DIR!!@$SCRIPT_SRC_DIR@g; + s@!!OSXAPP!!@$OSXAPP@g; + s@!!LANG_DIR!!@$LANG_DIR@g; + s@!!TTD!!@$TTD@g; + s@!!BINARY_DIR!!@$prefix_dir/$binary_dir@g; + s@!!DATA_DIR!!@$prefix_dir/$data_dir@g; + s@!!DOC_DIR!!@$prefix_dir/$doc_dir@g; + s@!!MAN_DIR!!@$prefix_dir/$man_dir@g; + s@!!ICON_DIR!!@$prefix_dir/$icon_dir@g; + s@!!ICON_THEME_DIR!!@$prefix_dir/$icon_theme_dir@g; + s@!!PERSONAL_DIR!!@$personal_dir@g; + s@!!SHARED_DIR!!@$shared_dir@g; + s@!!INSTALL_DIR!!@$install_dir@g; + s@!!BINARY_NAME!!@$binary_name@g; + s@!!STRGEN!!@$STRGEN@g; + s@!!ENDIAN_CHECK!!@$ENDIAN_CHECK@g; + s@!!DEPEND!!@$DEPEND@g; + s@!!SETTINGSGEN!!@$SETTINGSGEN@g; + s@!!ENDIAN_FORCE!!@$endian@g; + s@!!STAGE!!@$STAGE@g; + s@!!MAKEDEPEND!!@$makedepend@g; + s@!!CFLAGS_MAKEDEP!!@$cflags_makedep@g; + s@!!SORT!!@$sort@g; + s@!!CONFIG_CACHE_COMPILER!!@config.cache.compiler@g; + s@!!CONFIG_CACHE_LINKER!!@config.cache.linker@g; + s@!!CONFIG_CACHE_ENDIAN!!@config.cache.endian@g; + s@!!CONFIG_CACHE_SOURCE!!@config.cache.source@g; + s@!!CONFIG_CACHE_VERSION!!@config.cache.version@g; + s@!!CONFIG_CACHE_SOURCE_LIST!!@config.cache.source.list@g; + s@!!CONFIG_CACHE_PWD!!@config.cache.pwd@g; + s@!!LANG_SUPPRESS!!@$lang_suppress@g; + s@!!OBJS_C!!@$OBJS_C@g; + s@!!OBJS_CPP!!@$OBJS_CPP@g; + s@!!OBJS_MM!!@$OBJS_MM@g; + s@!!OBJS_RC!!@$OBJS_RC@g; + s@!!SRCS!!@$SRCS@g; + s@!!OS!!@$os@g; + s@!!CONFIGURE_FILES!!@$CONFIGURE_FILES@g; + s@!!AWK!!@$awk@g; + s@!!DISTCC!!@$distcc@g; + s@!!NFORENUM!!@$nforenum@g; + s@!!GRFCODEC!!@$grfcodec@g; + " + + if [ "$icon_theme_dir" != "" ]; then + SRC_REPLACE="$SRC_REPLACE + s@!!ICON_THEME_DIR!!@$prefix_dir/$icon_theme_dir@g; + " + else + SRC_REPLACE="$SRC_REPLACE + s@!!ICON_THEME_DIR!!@@g; + " + fi + + if [ "$man_dir" != "" ]; then + SRC_REPLACE="$SRC_REPLACE + s@!!MAN_DIR!!@$prefix_dir/$man_dir@g; + " + else + SRC_REPLACE="$SRC_REPLACE + s@!!MAN_DIR!!@@g; + " + fi + + if [ "$menu_dir" != "" ]; then + SRC_REPLACE="$SRC_REPLACE + s@!!MENU_DIR!!@$prefix_dir/$menu_dir@g; + " + else + SRC_REPLACE="$SRC_REPLACE + s@!!MENU_DIR!!@@g; + " + fi +} + +generate_menu_item() { + MENU_REPLACE=" + s@!!TTD!!@$TTD@g; + s@!!MENU_GROUP!!@$menu_group@g; + s@!!MENU_NAME!!@$menu_name@g + " + log 1 "Generating menu item..." + mkdir -p media + < $ROOT_DIR/media/openttd.desktop.in sed "$MENU_REPLACE" > media/openttd.desktop +} + +generate_main() { + STAGE="[MAIN]" + + make_sed + + # Create the main Makefile + log 1 "Generating Makefile..." + echo "# Auto-generated file from 'Makefile.in' -- DO NOT EDIT" > Makefile + < $ROOT_DIR/Makefile.in sed "$SRC_REPLACE" >> Makefile + cp $ROOT_DIR/Makefile.bundle.in Makefile.bundle + echo "# Auto-generated file -- DO NOT EDIT" > Makefile.am + echo >> Makefile.am + # Make the copy of the source-list, so we don't trigger an unwanted recompile + cp $SOURCE_LIST config.cache.source.list + # Add the current directory, so we don't trigger an unwanted recompile + echo "`pwd`" > config.cache.pwd + # Make sure config.cache is OLDER then config.cache.source.list + touch config.cache + touch config.pwd + + if [ "$menu_dir" != "" ]; then + generate_menu_item + fi +} + +generate_lang() { + STAGE="[LANG]" + + make_sed + + # Create the language file + mkdir -p $LANG_OBJS_DIR + + log 1 "Generating lang/Makefile..." + echo "# Auto-generated file from 'Makefile.lang.in' -- DO NOT EDIT" > $LANG_OBJS_DIR/Makefile + < $ROOT_DIR/Makefile.lang.in sed "$SRC_REPLACE" >> $LANG_OBJS_DIR/Makefile + echo "DIRS += $LANG_OBJS_DIR" >> Makefile.am + echo "LANG_DIRS += $LANG_OBJS_DIR" >> Makefile.am +} + +generate_settings() { + STAGE="[SETTING]" + + make_sed + + # Create the language file + mkdir -p $SETTING_OBJS_DIR + + log 1 "Generating setting/Makefile..." + echo "# Auto-generated file from 'Makefile.settings.in' -- DO NOT EDIT" > $SETTING_OBJS_DIR/Makefile + < $ROOT_DIR/Makefile.setting.in sed "$SRC_REPLACE" >> $SETTING_OBJS_DIR/Makefile + echo "DIRS += $SETTING_OBJS_DIR" >> Makefile.am +} + +generate_grf() { + STAGE="[BASESET]" + + make_sed + + # Create the language file + mkdir -p $GRF_OBJS_DIR + + log 1 "Generating grf/Makefile..." + echo "# Auto-generated file from 'Makefile.grf.in' -- DO NOT EDIT" > $GRF_OBJS_DIR/Makefile + < $ROOT_DIR/Makefile.grf.in sed "$SRC_REPLACE" >> $GRF_OBJS_DIR/Makefile + echo "DIRS += $GRF_OBJS_DIR" >> Makefile.am +} + +generate_src_normal() { + STAGE=$1 + + make_sed + + # Create the source file + mkdir -p $SRC_OBJS_DIR + + log 1 "Generating $2/Makefile..." + echo "# Auto-generated file from 'Makefile.src.in' -- DO NOT EDIT" > $SRC_OBJS_DIR/Makefile + < $ROOT_DIR/Makefile.src.in sed "$SRC_REPLACE" >> $SRC_OBJS_DIR/Makefile + echo "DIRS += $SRC_OBJS_DIR" >> Makefile.am + echo "SRC_DIRS += $SRC_OBJS_DIR" >> Makefile.am +} + +generate_src_osx() { + cc_host_orig="$cc_host" + cxx_host_orig="$cxx_host" + CFLAGS_orig="$CFLAGS" + LDFLAGS_orig="$LDFLAGS" + + for type in $enable_universal; do + + if [ -n "$osx_sdk_104_path" ]; then + # Use 10.4 SDK for 32-bit targets + CFLAGS="-isysroot $osx_sdk_104_path $CFLAGS_orig" + LDFLAGS="-Wl,-syslibroot,$osx_sdk_104_path $LDFLAGS_orig" + fi + + # We don't want to duplicate the x86_64 stuff for each target, so do it once here + if [ "$type" = "ppc64" ] || [ "$type" = "x86_64" ]; then + # 64 bits is always 10.5 or higher. Furthermore it has a non const ICONV + # and they also removed support for QuickTime/QuickDraw + if [ -n "$osx_sdk_path" ]; then + CFLAGS="-isysroot $osx_sdk_path $CFLAGS_orig" + LDFLAGS="-Wl,-syslibroot,$osx_sdk_path $LDFLAGS_orig" + fi + CFLAGS="$CFLAGS -D_SQ64 -DNO_QUICKTIME -UENABLE_COCOA_QUICKDRAW" + LIBS="`echo $LIBS | sed 's/-framework QuickTime//'`" + fi + + case $type in + ppc) + BASE_SRC_OBJS_DIR="$OBJS_DIR/ppc" + cc_host="$cc_host_orig -arch ppc -mmacosx-version-min=10.3" + cxx_host="$cxx_host_orig -arch ppc -mmacosx-version-min=10.3" + generate_src_normal "[ppc]" "objs/ppc";; + ppc970) + BASE_SRC_OBJS_DIR="$OBJS_DIR/ppc970" + cc_host="$cc_host_orig -arch ppc970 -mmacosx-version-min=10.3 -mcpu=G5 -mpowerpc64 -mtune=970 -mcpu=970 -mpowerpc-gpopt" + cxx_host="$cxx_host_orig -arch ppc970 -mmacosx-version-min=10.3 -mcpu=G5 -mpowerpc64 -mtune=970 -mcpu=970 -mpowerpc-gpopt" + generate_src_normal "[ppc970]" "objs/ppc970";; + i386) + BASE_SRC_OBJS_DIR="$OBJS_DIR/i386" + cc_host="$cc_host_orig -arch i386 -mmacosx-version-min=10.4" + cxx_host="$cxx_host_orig -arch i386 -mmacosx-version-min=10.4" + generate_src_normal "[i386]" "objs/i386";; + ppc64) + BASE_SRC_OBJS_DIR="$OBJS_DIR/ppc64" + cc_host="$cc_host_orig -arch ppc64 -mmacosx-version-min=10.5" + cxx_host="$cxx_host_orig -arch ppc64 -mmacosx-version-min=10.5" + generate_src_normal "[ppc64]" "objs/ppc64";; + x86_64) + BASE_SRC_OBJS_DIR="$OBJS_DIR/x86_64" + cc_host="$cc_host_orig -arch x86_64 -mmacosx-version-min=10.5" + cxx_host="$cxx_host_orig -arch x86_64 -mmacosx-version-min=10.5" + generate_src_normal "[x86_64]" "objs/x86_64";; + *) log 1 "Unknown architecture requested for universal build: $type";; + esac + done +} + +generate_src() { + if [ "$os" = "OSX" ] && [ "$enable_universal" != "0" ]; then + generate_src_osx + else + generate_src_normal "[SRC]" "objs" + fi +} + +showhelp() { + echo "'configure' configures OpenTTD." + echo "" + echo "Usage: $0 [OPTION]... [VAR=VALUE]..." + echo "" + echo "To assign environment variables (e.g., CC, CFLAGS...), specify them as" + echo "VAR=VALUE. See below for descriptions of some of the useful variables." + echo "" + echo "Defaults for the options are specified in brackets." + echo "" + echo "Configuration:" + echo " -h, --help display this help and exit" + echo "" + echo "System types:" + echo " --build=BUILD configure for building on BUILD [guessed]" + echo " --host=HOST cross-compile to build programs to run" + echo " on HOST [BUILD]" + echo " --windres=WINDRES the windres to use [HOST-windres]" + echo " --strip=STRIP the strip to use [HOST-strip]" + echo " --awk=AWK the awk to use in configure [awk]" + echo " --lipo=LIPO the lipo to use (OSX ONLY) [HOST-lipo]" + echo " --os=OS the OS we are compiling for [DETECT]" + echo " DETECT/UNIX/OSX/FREEBSD/DRAGONFLY/OPENBSD/" + echo " NETBSD/MORPHOS/HPUX/BEOS/SUNOS/CYGWIN/" + echo " MINGW/OS2/DOS/WINCE/PSP/HAIKU" + echo " --endian=ENDIAN set the endian of the HOST (AUTO/LE/BE)" + echo "" + echo "Paths:" + echo " --prefix-dir=dir specifies the prefix for all installed" + echo " files [/usr/local]" + echo " --binary-dir=dir location of the binary. Will be prefixed" + echo " with the prefix-dir [games]" + echo " --data-dir=dir location of data files (lang, data, gm)." + echo " Will be prefixed with the prefix-dir" + echo " [share/games/openttd]" + echo " --doc-dir=dir location of the doc files" + echo " Will be prefixed with the prefix-dir" + echo " [$doc_dir]" + echo " --icon-dir=dir location of icons. Will be prefixed" + echo " with the prefix-dir [share/pixmaps]" + echo " --icon-theme-dir=dir location of icon theme." + echo " Will be prefixed with the prefix-dir" + echo " and postfixed with size-dirs [$icon_theme_dir]" + echo " --man-dir=dir location of the manual page (UNIX only)" + echo " Will be prefixed with the prefix-dir" + echo " [$man_dir]" + echo " --menu-dir=dir location of the menu item. (UNIX only, except OSX)" + echo " Will be prefixed with the prefix-dir" + echo " [share/applications]" + echo " --personal-dir=dir location of the personal directory" + echo " [os-dependent default]" + echo " --shared-dir=dir location of shared data files" + echo " [os-dependent default]" + echo " --install-dir=dir specifies the root to install to." + echo " Useful to install into jails [/]" + echo " --binary-name the name used for the binary, icons," + echo " desktop file, etc. when installing [openttd]" + echo "" + echo "Features and packages:" + echo " --enable-debug[=LVL] enable debug-mode (LVL=[0123], 0 is release)" + echo " --enable-desync-debug=[LVL] enable desync debug options (LVL=[012], 0 is none" + echo " --enable-profiling enables profiling" + echo " --enable-lto enables GCC's Link Time Optimization (LTO)/ICC's" + echo " Interprocedural Optimization if available" + echo " --enable-dedicated compile a dedicated server (without video)" + echo " --enable-static enable static compile (doesn't work for" + echo " all HOSTs)" + echo " --enable-translator enable extra output for translators" + echo " --enable-universal[=ARCH] enable universal builds (OSX ONLY). Allowed is any combination" + echo " of architectures: i386 ppc ppc970 ppc64 x86_64" + echo " Default architectures are: i386 ppc" + echo " --enable-osx-g5 enables optimizations for ppc970 (G5) (OSX ONLY)" + echo " --disable-cocoa-quartz disable the quartz window mode driver for Cocoa (OSX ONLY)" + echo " --disable-cocoa-quickdraw disable the quickdraw window mode driver for Cocoa (OSX ONLY)" + echo " --disable-unicode disable unicode support to build win9x" + echo " version (Win32 ONLY)" + echo " --enable-console compile as a console application instead of as a GUI application." + echo " If this setting is active, debug output will appear in the same" + echo " console instead of opening a new window. (Win32 ONLY)" + echo " --disable-network disable network support" + echo " --disable-assert disable asserts (continue on errors)" + echo " --enable-strip enable any possible stripping" + echo " --without-osx-sysroot disable the automatic adding of sysroot " + echo " (OSX ONLY)" + echo " --without-application-bundle disable generation of application bundle" + echo " (OSX ONLY)" + echo " --without-menu-entry Don't generate a menu item (Freedesktop based only)" + echo " --menu-group=group Category in which the menu item will be placed (Freedesktop based only)" + echo " --menu-name=name Name of the menu item when placed [OpenTTD]" + echo " --with-direct-music enable direct music support (Win32 ONLY)" + echo " --with-sort=sort define a non-default location for sort" + echo " --with-midi=midi define which midi-player to use" + echo " --with-midi-arg=arg define which args to use for the" + echo " midi-player" + echo " --with-libtimidity enables libtimidity support" + echo " --with-allegro[=allegro-config]" + echo " enables Allegro video driver support" + echo " --with-cocoa enables COCOA video driver (OSX ONLY)" + echo " --with-sdl[=sdl-config] enables SDL video driver support" + echo " --with-zlib[=zlib.a] enables zlib support" + echo " --with-liblzma[=\"pkg-config liblzma\"]" + echo " enables liblzma support" + echo " --with-liblzo2[=liblzo2.a] enables liblzo2 support" + echo " --with-png[=libpng-config] enables libpng support" + echo " --with-freetype[=freetype-config]" + echo " enables libfreetype support" + echo " --with-fontconfig[=\"pkg-config fontconfig\"]" + echo " enables fontconfig support" + echo " --with-xdg-basedir[=\"pkg-config libxdg-basedir\"]" + echo " enables XDG base directory support" + echo " --with-icu[=icu-config] enables icu (used for right-to-left support)" + echo " --static-icu try to link statically (libsicu instead of" + echo " libicu; can fail as the new name is guessed)" + echo " --with-iconv[=iconv-path] enables iconv support" + echo " --with-psp-config[=psp-config] enables psp-config support (PSP ONLY)" + echo " --disable-builtin-depend disable use of builtin deps finder" + echo " --with-makedepend[=makedepend] enables makedepend support" + echo " --with-ccache enables ccache support" + echo " --with-distcc enables distcc support" + echo " --without-grfcodec disable usage of grfcodec and re-generation of base sets" + echo " --without-threads disable threading support" + echo " --without-sse disable SSE support (x86/x86_64 only)" + echo "" + echo "Some influential environment variables:" + echo " CC C compiler command" + echo " CXX C++ compiler command" + echo " CFLAGS C compiler flags" + echo " CXXFLAGS C++ compiler flags" + echo " WINDRES windres command" + echo " LDFLAGS linker flags, e.g. -L if you" + echo " have libraries in a nonstandard" + echo " directory " + echo " CFLAGS_BUILD C compiler flags for build time tool generation" + echo " CXXFLAGS_BUILD C++ compiler flags for build time tool generation" + echo " LDFLAGS_BUILD linker flags for build time tool generation" + echo "" + echo "Use these variables to override the choices made by 'configure' or to help" + echo "it to find libraries and programs with nonstandard names/locations." +} diff --git a/config.log b/config.log new file mode 100644 index 0000000..b279d15 --- /dev/null +++ b/config.log @@ -0,0 +1,144 @@ + +Invocation: ./configure --enable-dedicated +Detecing awk... +Trying: echo "a.c b.c c.c" | tr ' ' \n | awk ' { ORS = " " } /\.c$/ { gsub(".c$", ".o", $0); print $0; }' 2>/dev/null +Result: 'a.o b.o c.o ' +checking awk... awk +detecting OS... UNIX +checking build system type... CC/CXX not set (skipping) +executing gcc -dumpmachine + returned x86_64-linux-gnu + exit code 0 +checking build system type... x86_64-linux-gnu +checking host system type... CC/CXX not set (skipping) +executing gcc -dumpmachine + returned x86_64-linux-gnu + exit code 0 +checking host system type... x86_64-linux-gnu +checking universal build... no +checking build cc... gcc +checking host cc... gcc +checking build c++... CC/CXX not set (skipping) +executing g++ -dumpmachine + returned x86_64-linux-gnu + exit code 0 +checking build c++... g++ +checking host c++... CC/CXX not set (skipping) +executing g++ -dumpmachine + returned x86_64-linux-gnu + exit code 0 +checking host c++... g++ +checking host strip... CC/CXX not set (skipping) +executing strip -V + returned GNU strip (GNU Binutils for Ubuntu) 2.25 +Copyright (C) 2014 Free Software Foundation, Inc. +This program is free software; you may redistribute it under the terms of +the GNU General Public License version 3 or (at your option) any later version. +This program has absolutely no warranty. + exit code 0 +checking host strip... strip +checking builtin depend... yes +checking makedepend... disabled +executing g++ tmp.64bit.cpp -o tmp.64bit -DTESTING 2>&1 + returned + exit code 0 +detecting cpu-type... 64 bits +executing g++ -msse4.1 tmp.sse.cpp -o tmp.sse 2>&1 + returned + exit code 0 +detecting SSE... found +checking static... no +checking unicode... no +using debug level... no +using desync debug level... no +using link time optimization... no +checking OSX sysroot... not OSX, skipping +checking Allegro... dedicated server, skipping +checking SDL... dedicated server, skipping +checking COCOA... dedicated server, skipping +checking GDI video driver... dedicated server, skipping +checking dedicated... found +checking console application... not Windows, skipping +checking network... found +checking squirrel... found +checking translator... no +checking assert... disabled +detecting zlib + trying /usr/include/zlib.h... found +checking zlib... found +detecting liblzma +executing pkg-config liblzma --modversion + returned 5.1.0alpha + exit code 0 +checking liblzma... found +detecting lzo2 + trying /usr/include/lzo/lzo1x.h... found +checking lzo2... found +detecting libxdg-basedir +executing pkg-config libxdg-basedir --modversion + returned + exit code 1 +checking libxdg-basedir... not found +detecting libpng +executing pkg-config libpng --modversion + returned 1.2.51 + exit code 0 +checking libpng... found +checking libfreetype... dedicated server, skipping +checking libfontconfig... dedicated server, skipping +checking libicu... dedicated server, skipping +checking psp-config... not PSP, skipping +detecting libtimidity + trying /usr/include/timidity.h... no + trying /usr/local/include/timidity.h... no + trying /mingw/include/timidity.h... no + trying /opt/local/include/timidity.h... no +checking libtimidity... not found +checking direct-music... not Windows, skipping +running echo | sort + result was valid +checking sort... sort +checking endianness... AUTO +suppress language errors... no +checking stripping... strip -s +checking distcc... no (only used when forced) +checking ccache... no (only used when forced) +executing grfcodec -v + returned + exit code 0 +checking grfcodec... not found +executing nforenum -v + returned + exit code 0 +checking nforenum... not found +checking OSX application bundle... not OSX, skipping +checking revision... no detection +WARNING: there is no means to determine the version. +WARNING: please use a subversion, mercurial, or git checkout of OpenTTD. +WARNING: you can only join game servers that have been compiled without +WARNING: version detection. +WARNING: there is a great chance you desync. +WARNING: USE WITH CAUTION! +checking iconv... not OSX, skipping +personal home directory... .openttd +shared data directory... none +installation directory... / +icon theme directory... share/icons/hicolor +manual page directory... share/man/man6 +menu item directory... share/applications +Running configure with following options: + +./configure --ignore-extra-parameters --build="" --host="" --cc-build="gcc" --cc-host="gcc" --cxx-build="g++" --cxx-host="g++" --windres="" --strip="strip" --lipo="" --awk="awk" --os="UNIX" --endian="AUTO" --cpu-type="64" --config-log="config.log" --prefix-dir="/usr/local" --binary-dir="games" --data-dir="share/games/openttd" --doc-dir="share/doc/openttd" --icon-dir="share/pixmaps" --icon-theme-dir="share/icons/hicolor" --man-dir="share/man/man6" --menu-dir="share/applications" --personal-dir=".openttd" --shared-dir="" --install-dir="/" --menu-group="Game;" --menu-name="OpenTTD" --binary-name="openttd" --enable-debug="0" --enable-desync-debug="0" --enable-profiling="0" --enable-lto="0" --enable-dedicated="1" --enable-network="1" --enable-static="0" --enable-translator="0" --enable-unicode="0" --enable-console="1" --enable-assert="0" --enable-strip="1" --enable-universal="0" --enable-osx-g5="0" --enable-cocoa-quartz="1" --enable-cocoa-quickdraw="1" --with-osx-sysroot="0" --with-application-bundle="0" --with-allegro="1" --with-sdl="1" --with-cocoa="0" --with-zlib="1" --with-lzma="1" --with-lzo2="1" --with-xdg-basedir="1" --with-png="1" --enable-builtin-depend="1" --with-makedepend="0" --with-direct-music="0" --with-sort="1" --with-iconv="0" --with-midi="" --with-midi-arg="" --with-libtimidity="0" --with-freetype="1" --with-fontconfig="1" --with-icu="1" --static-icu="0" --with-psp-config="1" --with-threads="1" --with-distcc="0" --with-ccache="0" --with-grfcodec="1" --with-nforenum="1" --with-sse="1" --CC="" --CXX="" --CFLAGS="" --CXXFLAGS="" --LDFLAGS="" --CFLAGS-BUILD="" --CXXFLAGS-BUILD="" --LDFLAGS-BUILD="" + +using CFLAGS_BUILD... -Wall -Wno-multichar -Wsign-compare -Wundef -Wwrite-strings -Wpointer-arith -W -Wno-unused-parameter -Wredundant-decls -Wformat=2 -Wformat-security -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-but-set-parameter -Winit-self -fno-strict-aliasing -Wcast-qual -fno-strict-overflow -Wnon-virtual-dtor -Wno-free-nonheap-object -rdynamic -DUNIX -D_FORTIFY_SOURCE=2 -O1 -DNDEBUG +using CXXFLAGS_BUILD... -std=gnu++0x -Wno-narrowing +using LDFLAGS_BUILD... -rdynamic +using CFLAGS... -O2 -fomit-frame-pointer -Wall -Wno-multichar -Wsign-compare -Wundef -Wwrite-strings -Wpointer-arith -W -Wno-unused-parameter -Wredundant-decls -Wformat=2 -Wformat-security -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-but-set-parameter -Winit-self -fno-strict-aliasing -Wcast-qual -fno-strict-overflow -Wnon-virtual-dtor -Wno-free-nonheap-object -rdynamic -DUNIX -D_FORTIFY_SOURCE=2 -DWITH_SSE -DWITH_ZLIB -DWITH_LZMA -DWITH_LZO -D_SQ64 -I/home/openttd/openttd-virj-source/src/3rdparty/squirrel/include -DWITH_PNG -I/usr/include/libpng12 -DDEDICATED -DENABLE_NETWORK -DNDEBUG -DWITH_PERSONAL_DIR -DPERSONAL_DIR=\".openttd\" -DGLOBAL_DATA_DIR=\"/usr/local/share/games/openttd\" +using CXXFLAGS... -std=gnu++0x -Wno-narrowing +using LDFLAGS... -lstdc++ -lpthread -lc -lz -llzma -llzo2 -lpng12 -rdynamic +Generating Makefile... +Generating menu item... +Generating lang/Makefile... +Generating setting/Makefile... +Generating grf/Makefile... +Generating objs/Makefile... diff --git a/config.pwd b/config.pwd new file mode 100644 index 0000000..e69de29 diff --git a/configure b/configure new file mode 100755 index 0000000..6b2c9d8 --- /dev/null +++ b/configure @@ -0,0 +1,175 @@ +#!/bin/sh + +# $Id$ + +# This file is part of OpenTTD. +# OpenTTD 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, version 2. +# OpenTTD 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 OpenTTD. If not, see . + +check_path_characters() { + if [ -n "`echo $ROOT_DIR | grep '[^-_A-Za-z0-9\/\\\.:]'`" ]; then + echo "WARNING: The path contains a non-alphanumeric character that might cause" + echo " failures in subsequent build stages. Any failures with the build" + echo " will most likely be caused by this." + fi +} + +CONFIGURE_EXECUTABLE="$_" +# On *nix systems those two are equal when ./configure is done +if [ "$0" != "$CONFIGURE_EXECUTABLE" ]; then + # On some systems, when ./configure is triggered from 'make' + # the $_ is filled with 'make'. So if that is true, skip 'make' + # and use $0 (and hope that is correct ;)) + if [ -n "`echo $CONFIGURE_EXECUTABLE | grep make`" ]; then + CONFIGURE_EXECUTABLE="$0" + else + CONFIGURE_EXECUTABLE="$CONFIGURE_EXECUTABLE $0" + fi +fi +# Find out where configure is (in what dir) +ROOT_DIR="`dirname $0`" +# For MSYS/MinGW we want to know the FULL path. This as that path is generated +# once you call an outside binary. Having the same path for the rest is needed +# for dependency checking. +# pwd -W returns said FULL path, but doesn't exist on others so fall back. +ROOT_DIR="`cd $ROOT_DIR && (pwd -W 2>/dev/null || pwd 2>/dev/null)`" + +check_path_characters + +# Same here as for the ROOT_DIR above +PWD="`pwd -W 2>/dev/null || pwd 2>/dev/null`" +PREFIX="$PWD/bin" + +. $ROOT_DIR/config.lib + +# Set default dirs +OBJS_DIR="$PWD/objs" +BASE_SRC_OBJS_DIR="$OBJS_DIR" +LANG_OBJS_DIR="$OBJS_DIR/lang" +GRF_OBJS_DIR="$OBJS_DIR/extra_grf" +SETTING_OBJS_DIR="$OBJS_DIR/setting" +BIN_DIR="$PREFIX" +SRC_DIR="$ROOT_DIR/src" +LANG_DIR="$SRC_DIR/lang" +MEDIA_DIR="$ROOT_DIR/media" +SOURCE_LIST="$ROOT_DIR/source.list" + +if [ "$1" = "--reconfig" ] || [ "$1" = "--reconfigure" ]; then + if [ ! -f "config.cache" ]; then + echo "can't reconfigure, because never configured before" + exit 1 + fi + # Make sure we don't lock config.cache + cat config.cache | sed 's@\\ @\\\\ @g' > cache.tmp + sh cache.tmp + RET=$? + rm -f cache.tmp + exit $RET +fi + +set_default +detect_params "$@" +check_params +save_params +make_cflags_and_ldflags + +EXE="" +if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "OS2" ] || [ "$os" = "DOS" ] || [ "$os" = "WINCE" ]; then + EXE=".exe" +fi + +TTD="openttd$EXE" +STRGEN="strgen$EXE" +ENDIAN_CHECK="endian_check$EXE" +DEPEND="depend$EXE" +SETTINGSGEN="settings_gen$EXE" + +if [ -z "$sort" ]; then + PIPE_SORT="sed s@a@a@" +else + PIPE_SORT="$sort" +fi + +if [ ! -f "$LANG_DIR/english.txt" ]; then + echo "Languages not found in $LANG_DIR. Can't continue without it." + echo "Please make sure the dir exists and contains at least english.txt" +fi + +# Read the source.list and process it +AWKCOMMAND=' + { } + /^( *)#end/ { if (deep == skip) { skip -= 1; } deep -= 1; next; } + /^( *)#else/ { if (deep == skip) { skip -= 1; } else if (deep - 1 == skip) { skip += 1; } next; } + /^( *)#if/ { + gsub(" ", "", $0); + gsub("^#if ", "", $0); + + if (deep != skip) { deep += 1; next; } + + deep += 1; + + if ($0 == "ALLEGRO" && "'$allegro_config'" == "") { next; } + if ($0 == "SDL" && "'$sdl_config'" == "") { next; } + if ($0 == "PNG" && "'$png_config'" == "") { next; } + if ($0 == "OSX" && "'$os'" != "OSX") { next; } + if ($0 == "OS2" && "'$os'" != "OS2") { next; } + if ($0 == "PSP" && "'$os'" != "PSP") { next; } + if ($0 == "DEDICATED" && "'$enable_dedicated'" != "1") { next; } + if ($0 == "AI" && "'$enable_ai'" == "0") { next; } + if ($0 == "COCOA" && "'$with_cocoa'" == "0") { next; } + if ($0 == "DOS" && "'$os'" != "DOS") { next; } + if ($0 == "BEOS" && "'$os'" != "BEOS" && + "'$os'" != "HAIKU") { next; } + if ($0 == "WIN32" && "'$os'" != "MINGW" && + "'$os'" != "CYGWIN" && "'$os'" != "MSVC") { next; } + if ($0 == "MORPHOS" && "'$os'" != "MORPHOS") { next; } + if ($0 == "WINCE" && "'$os'" != "WINCE") { next; } + if ($0 == "MSVC" && "'$os'" != "MSVC") { next; } + if ($0 == "DIRECTMUSIC" && "'$with_direct_music'" == "0") { next; } + if ($0 == "LIBTIMIDITY" && "'$libtimidity'" == "" ) { next; } + if ($0 == "HAVE_THREAD" && "'$with_threads'" == "0") { next; } + if ($0 == "SSE" && "'$with_sse'" != "1") { next; } + + skip += 1; + + next; + } + /^( *)#/ { next } + /^$/ { next } + /\.h$/ { next } + /\.hpp$/ { next } + { + if (deep == skip) { + gsub(" ", "", $0); + print $0; + } + } +' + +# Read the source.list and process it +# Please escape ALL " within ` because e.g. "" terminates the string in some sh implementations +SRCS="`< $ROOT_DIR/source.list tr '\r' '\n' | $awk \"$AWKCOMMAND\" | $PIPE_SORT`" + +OBJS_C="` echo \"$SRCS\" | $awk ' { ORS = \" \" } /\.c$/ { gsub(\".c$\", \".o\", $0); print $0; }'`" +OBJS_CPP="`echo \"$SRCS\" | $awk ' { ORS = \" \" } /\.cpp$/ { gsub(\".cpp$\", \".o\", $0); print $0; }'`" +OBJS_MM="` echo \"$SRCS\" | $awk ' { ORS = \" \" } /\.mm$/ { gsub(\".mm$\", \".o\", $0); print $0; }'`" +OBJS_RC="` echo \"$SRCS\" | $awk ' { ORS = \" \" } /\.rc$/ { gsub(\".rc$\", \".o\", $0); print $0; }'`" +SRCS="` echo \"$SRCS\" | $awk ' { ORS = \" \" } { print $0; }'`" + +# In makefiles, we always use -u for sort +if [ -z "$sort" ]; then + sort="sed s@a@a@" +else + sort="$sort -u" +fi + +CONFIGURE_FILES="$ROOT_DIR/configure $ROOT_DIR/config.lib $ROOT_DIR/Makefile.in $ROOT_DIR/Makefile.grf.in $ROOT_DIR/Makefile.lang.in $ROOT_DIR/Makefile.src.in $ROOT_DIR/Makefile.bundle.in $ROOT_DIR/Makefile.setting.in" + +generate_main +generate_lang +generate_settings +generate_grf +generate_src + +check_path_characters diff --git a/docs/HOWTO_compile_lang_files.txt b/docs/HOWTO_compile_lang_files.txt new file mode 100644 index 0000000..c56f97a --- /dev/null +++ b/docs/HOWTO_compile_lang_files.txt @@ -0,0 +1,72 @@ +OpenTTD and strgen +Last updated: 2009-06-30 +------------------------------------------------------------------------ + + +Table of contents +----------------- +1.0) strgen usage + * 1.1) Examples + * 1.2) strgen command switches + + +1.0) strgen usage +---- ------------ +This guide is only interesting for people who want to alter something +themselves without access to translator.openttd.org. Please note that +your compiled language file will only be compatible with the OpenTTD version +you have downloaded english.txt, the master language file, for. While this is +not always true, namely when changes in the code have not touched language +files, your safest bet is to assume this 'limitation'. +As a first step you need to compile strgen. This is as easy as typing +'make strgen'. You can download the precompile strgen from: +http://www.openttd.org/download-strgen + +strgen takes as argument a txt file and translates it to a lng file, allowing +it to be used inside OpenTTD. strgen needs the master language file +english.txt to work. Below are some examples of strgen usage. + +1.1) Examples +---- -------- +Example 1: +if you are in the root of your working copy (svn code), you should type +strgen/strgen -s lang lang/english.txt +to compile englist.txt into english.lng. It will be placed in the lang dir + +Example 2: +you only have the strgen executable (no working copy) and you want to compile +a txt file in the same directory. You should type +./strgen english.txt +and you will get and english.lng in the same dir + +Example 3: +you have strgen somewhere, english.txt in /usr/openttd/lang and you want the +resulting language file to go to /tmp. Use +./strgen -s /usr/openttd/lang -d /tmp english.txt + +You can interchange english.txt to whichever language you want to generate a +.lng file for. + +1.2) strgen command switches +---- ----------------------- +-v | --version +strgen will tell what svn revision it was last modified + +-t | --todo +strgen will add to any untranslated/missing strings and use the english +strings while compiling the language file + +-w | --warning +strgen will print any missing strings or wrongly translated (bad format) +to standard error output(stderr) + +-h | --help | -? +Print out a summarized help message explaining these switches + +-s | --source_dir +strgen will search for the master file english.txt in the directory specified +by this switch instead of the current directory + +-d | --dest_dir +strgen will put .lng in the directory specified by this switch; if +no dest_dir is given, output is the same as source_dir diff --git a/docs/Readme_OS2.txt b/docs/Readme_OS2.txt new file mode 100644 index 0000000..84fa6ec --- /dev/null +++ b/docs/Readme_OS2.txt @@ -0,0 +1,139 @@ +OpenTTD: OS/2 version +===================== + +OpenTTD has been ported to work on OS/2 4.x or later (including +eComStation). The game should work as well as it does on Windows +or other platforms: the main issues you may encounter are graphics +card problems, but that is really the fault of SDL. + +========================= +USING OPENTTD FOR OS/2 +========================= + +LIBRARIES REQUIRED FOR END USERS +-------------------------------- + +SDL.DLL (SDL 1.2.7) and FSLib.dll are required to use this program: +these can be downloaded from the Files section at +http://sourceforge.net/projects/openttd/ - see "os2-useful-v1.1.zip". +Version 20051222 of SDL or later is required. This can be found at +http://sdl.netlabs.org/. + +Please note that earlier SDL releases will probably NOT work with +OpenTTD. If you experience problems with OpenTTD, please check +your SDL and FSLib.dll versions (both must match). + +Note that to actually play the game, I have found in my own +experience that a version of the Scitech Display Drivers or its later +incarnation (see www.scitech.com) are necessary for it to work. If +you have trouble with your native drivers, try the Scitech drivers +and see if they help the problem. + +KNOWN ISSUES +------------ + +- If an error occurs during loading, the OS/2 error message window + is not always displayed. + +A NOTE ABOUT MUSIC +------------------ + +OpenTTD includes a music driver which uses the MCI MIDI system. Unfortunately, +due to the lack of proper MIDI hardware myself, I have been unable to test it, +but during testing, I found that when MIDI was enabled, I got no sound +effects. I therefore decided to DISABLE music by default. + +To enable music, start OpenTTD with the command line: + + openttd -m os2 + +If I hear enough responses that both music and sound work together (it might +just be my system), I'll have the defaults changed. + +Please note also that the GCC version does not currently support the MCI MIDI +system. + + +A NOTE ABOUT DEDICATED MULTIPLAYER SERVERS +------------------------------------------ + +To start a dedicated multiplayer server, you should run the dedicated.cmd +file. This enables OpenTTD to open up a VIO console window to display +its output and gather any necessary input. Running "openttd -D" +directly will result in the console not being displayed. You may +still pass any other parameters ('-D' is already passed) to +dedicated.cmd. + +You can find the dedicated.cmd file in the os/os2 directory. + +========================= +BUILDING THE OS/2 VERSION +========================= + +Compiler +-------- + +Innotek GCC, an OS/2 port of the popular GCC compiler, was used to build OpenTTD. +See www.innotek.de for more information. You WILL need a reasonably UNIX-like +build environment in order to build OpenTTD successfully - the following link +may help to set one up (although some of the links from that page are broken): + + http://www.mozilla.org/ports/os2/gccsetup.html + +Alternatively, Paul Smedley's ready-to-go GCC build environment has been known to +successfully build the game: + + http://www.smedley.info/os2ports/index.php?page=build-environment + +To build, you should, if your environment is set up well enough, be able to just +type `./configure' (or `sh configure' if you're using the OS/2 shell) and `make'. + +You may have to manually specify `--os OS2' on the configure command line, as +configure cannot always detect OS/2 correctly. + +A note on Open Watcom +--------------------- + +Open Watcom C/C++ was previously used to build OpenTTD (version 0.4.x and earlier). +However, due to advanced C++ features used in the YAPF portion of OpenTTD 0.5 +in particular, the compiler is no longer able to build the game at the moment. +Hopefully one day Open Watcom will be able to catch up and we will be able to build +the game once again (it's easier than getting an OS/2 UNIX-like environment set up +in my opinion!), but until then, OpenTTD 0.5 and later can only be built with GCC. + +Libraries Required +------------------ + +The following libraries are required. To build zlib and libpng, I +simply added the required files (watch out for sample programs, etc) +to an IDE project file and built a library. Do not use the makefiles +provided, they are not designed for Watcom (apart from SDL): + +- zlib + http://www.zlib.org/ + +- libpng + http://www.libpng.org/ + +- SDL for OS/2 + ftp://ftp.netlabs.org/pub/sdl/sdl-1.2.7-src-20051222.zip used for + 0.4.7 + +- Freetype + http://freetype.sourceforge.net/ + +Currently, there are no pre-built libraries available for GCC. If you manage to get +OpenTTD working on Watcom though (do let us know if this is the case!), pre-built +versions can be downloaded from the Files section at +http://sourceforge.net/projects/openttd/ - see "os2-useful-v1.1.zip". + +Contact Information +------------------- + +If you have any questions regarding OS/2 issues, please contact me +(owen@owenrudge.net) and I'll try to help you out. For general OpenTTD +issues, see the Contacting section of readme.txt. + +Thanks to Paul Smedley for his help with getting OpenTTD to compile under GCC on OS/2. + +- Owen Rudge, 24th June 2007 diff --git a/docs/Readme_Windows_MSVC.txt b/docs/Readme_Windows_MSVC.txt new file mode 100644 index 0000000..637b28b --- /dev/null +++ b/docs/Readme_Windows_MSVC.txt @@ -0,0 +1,108 @@ +Compiling OpenTTD using Microsoft Visual C++ +Last updated: 2010-01-03 +-------------------------------------------- +PLEASE READ THE ENTIRE DOCUMENT BEFORE DOING ANY ACTUAL CHANGES!! + + +SUPPORTED MSVC COMPILERS +------------------------ +OpenTTD includes projects for MSVC 2005.NET and MSVC 2008.NET. Both will +compile out of the box, providing you have the required libraries/headers; +which ones, see below. There is no support for VS6 or MSVC 2002, or +MSVC 2003.NET. You are therefore strongly encouraged to either upgrade to +MSVC 2008 Express (free) or use GCC. + + +1) REQUIRED FILES +----------------- +You might already have some of the files already installed, so check before +downloading; mostly because the DirectX SDK and Platform SDK are about +500MB each. +Download the following files: + + * openttd-useful.zip (http://binaries.openttd.org/extra/openttd-useful/) + * DirectX 8.1 SDK (http://neuron.tuke.sk/~mizanin/eng/Dx81sdk-include-lib.rar) (or alternatively the latest DirectX SDK from Microsoft) + * MS Windows Platform SDK (http://www.microsoft.com/downloads/details.aspx?FamilyId=A55B6B43-E24F-4EA3-A93E-40C0EC4F68E5&displaylang=en) + * afxres.h (http://www-d0.fnal.gov/d0dist/dist/packages/d0ve/devel/windows/AFXRES.H) + +...and of course the newest source from svn://svn.openttd.org/trunk + +You need an SVN-client to download the source from subversion: + + * CLI Subversion (http://subversion.tigris.org/) + * GUI TortoiseSVN (http://tortoisesvn.tigris.org/) + + +2) INCLUDES AND LIBRARIES +------------------------- +Put the newly downloaded files in the VC lib\ and include\ directories; where +"C:\Program Files\Microsoft Visual Studio 9.0\VC" is your location of Visual C. +If you are compiling for an x64 system, use the include\ and lib\ directories +from the win64/ folder. + + * openttd-useful.zip\include\* + * afxresh.h + to > C:\Program Files\Microsoft Visual Studio 9.0\VC\Include + + * openttd-useful.zip\lib\* + to > C:\Program Files\Microsoft Visual Studio 9.0\VC\Lib + +Custom directories might be recommended, check 2.2) + + +2.1) INCLUDES AND LIBRARIES - DIRECTX/PLATFORM SDK +-------------------------------------------------- +Basically the same procedure as with the useful zip file, providing +you are not using the Microsoft installer. Put the include files in the +include\ directory and the library files to the Lib\ directory. + +It is recommended to use custom directories so you don't overwrite any +default header or library files. + + +2.2) CUSTOM DIRECTORIES +----------------------- +If you have put the above include and/or library files into custom folders, +MSVC will not find them by default. You need to add these paths to VC through: + +Tools > Options > Projects and Solutions > VC++ Directories > show directories for + + * Include files: Add the DirectX/Platform SDK include dir you've created + * Library files: Add the path to the SDK custom lib dir + +NOTE: make sure that the directory for the DirectX SDK is the first one in the +list, above all others, otherwise compilation will most likely fail!! + + +3) TTD GRAPHICS FILES +--------------------- +See section 4.1 of readme.txt for the required 3rdparty files and how to install them. + + +4) COMPILING +------------ +Open trunk/openttd_vs[89]0.sln +Set the build mode to 'Release' in +Build > Configuration manager > Active solution configuration > select "Release" +Compile... + +If everything works well the binary should be in trunk/objs/Win[32|64]/Release/openttd.exe + + +5) EDITING, CHANGING SOURCE CODE +-------------------------------- +Set the build mode (back to) 'Debug' +Change the startup project to openttd by right-clicking the 'openttd' project +in the Solution Explorer and selecting 'Set as Startup Project'. The 'openttd' +project should now show up bold instead of 'strgen'. + + +6) PROBLEMS? +------------ +If compilation fails, double-check that you are using the latest SVN (!) +source. If it still doesn't work, check in on IRC (irc://irc.oftc.net/openttd), +to ask about reasons; or just wait. The problem will most likely solve itself +within a few days as the problem is noticed and fixed. + +An up-to-date version of this README can be found on the wiki: +http://wiki.openttd.org/Microsoft_Visual_C%2B%2B_2008_Express_Editions diff --git a/docs/admin_network.txt b/docs/admin_network.txt new file mode 100644 index 0000000..904f3ca --- /dev/null +++ b/docs/admin_network.txt @@ -0,0 +1,219 @@ +OpenTTD's admin network +Last updated: 2011-01-20 +------------------------------------------------------------------------ + + +Table of contents +----------------- +1.0) Preface +2.0) Joining the network +3.0) Asking for updates + * 3.1) Polling manually +4.0) Sending rcon commands +5.0) Sending chat + * 5.1) Receiving chat +6.0) Disconnecting +7.0) Certain packet information + + +1.0) Preface +---- ------- + The admin network provides a dedicated network protocol designed for other + applications to communicate with OpenTTD. Connected applications can execute + console commands remotely (rcon commands) with no further authentication. + Furthermore information about clients and companies can be provided. + + Admin applications remain connected when starting a new game or loading a saved + game in contrast to normal OpenTTD clients that get disconnected. + + This document describes the admin network and its protocol. + + Please refer to the mentioned enums in src/network/core/tcp_admin.h + + Please also note that further improvements to the admin protocol can mean that + more packet types will be sent by the server. For forward compatibility it is + therefore wise to ignore unknown packets. Future improvements might also add + additional data to packets. This data should be ignored. Data will never be + removed from packets in later versions, except the possibility that complete + packets are dropped in favour of a new packet. + This though will be reflected in the protocol version as announced in the + ADMIN_PACKET_SERVER_PROTOCOL in section 2.0). + + A reference implementation in Java for a client connecting to the admin interface + can be found at: http://dev.openttdcoop.org/projects/joan + + +2.0) Joining the network +---- ------------------- + Create a TCP connection to the server on port 3977. The application is + expected to authenticate within 10 seconds. + + To authenticate send a ADMIN_PACKET_ADMIN_JOIN packet. + + The server will reply with ADMIN_PACKET_SERVER_PROTOCOL followed directly by + ADMIN_PACKET_SERVER_WELCOME. + + ADMIN_PACKET_SERVER_PROTOCOL contains details about the protocol version. + It is the job of your application to check this number and decide whether + it will remain connected or not. + Furthermore, this packet holds details on every AdminUpdateType and the + supported AdminFrequencyTypes (bitwise representation). + + ADMIN_PACKET_SERVER_WELCOME contains details on the server and the map, + e.g. if the server is dedicated, its NetworkLanguage, size of the Map, etc. + + Once you have received ADMIN_PACKET_SERVER_WELCOME you are connected and + authorized to do your thing. + The server will not provide any game related updates unless you ask for them. + There are four packets the server will none the less send, if applicable: + - ADMIN_PACKET_SERVER_ERROR + - ADMIN_PACKET_SERVER_WELCOME + - ADMIN_PACKET_SERVER_NEWGAME + - ADMIN_PACKET_SERVER_SHUTDOWN + + However, ADMIN_PACKET_SERVER_WELCOME only after a ADMIN_PACKET_SERVER_NEWGAME + + +3.0) Asking for updates +---- ------------------ + Asking for updates is done with ADMIN_PACKET_ADMIN_UPDATE_FREQUENCY. + With this packet you define which update you wish to receive at which + frequency. + + Note: not every update type supports every frequency. If in doubt, you can + verify against the data received in ADMIN_PACKET_SERVER_PROTOCOL. + + The server will not confirm your registered update. However, asking for an + invalid AdminUpdateType or a not supported AdminUpdateFrequency you will be + disconnected from the server with NETWORK_ERROR_ILLEGAL_PACKET. + + Additional debug information can be found with a debug level of net=3. + + ADMIN_UPDATE_DATE results in the server sending: + - ADMIN_PACKET_SERVER_DATE + + ADMIN_UPDATE_CLIENT_INFO results in the server sending: + - ADMIN_PACKET_SERVER_CLIENT_JOIN + - ADMIN_PACKET_SERVER_CLIENT_INFO + - ADMIN_PACKET_SERVER_CLIENT_UPDATE + - ADMIN_PACKET_SERVER_CLIENT_QUIT + - ADMIN_PACKET_SERVER_CLIENT_ERROR + + ADMIN_UPDATE_COMPANY_INFO results in the server sending: + - ADMIN_PACKET_SERVER_COMPANY_NEW + - ADMIN_PACKET_SERVER_COMPANY_INFO + - ADMIN_PACKET_SERVER_COMPANY_UPDATE + - ADMIN_PACKET_SERVER_COMPANY_REMOVE + + ADMIN_UPDATE_COMPANY_ECONOMY results in the server sending: + - ADMIN_PACKET_SERVER_COMPANY_ECONOMY + + ADMIN_UPDATE_COMPANY_STATS results in the server sending: + - ADMIN_PACKET_SERVER_COMPANY_STATS + + ADMIN_UPDATE_CHAT results in the server sending: + - ADMIN_PACKET_SERVER_CHAT + + ADMIN_UPDATE_CONSOLE results in the server sending: + - ADMIN_PACKET_SERVER_CONSOLE + + + ADMIN_UPDATE_CMD_LOGGING results in the server sending: + - ADMIN_PACKET_SERVER_CMD_LOGGING + +3.1) Polling manually +---- ---------------- + Certain AdminUpdateTypes can also be polled: + - ADMIN_UPDATE_DATE + - ADMIN_UPDATE_CLIENT_INFO + - ADMIN_UPDATE_COMPANY_INFO + - ADMIN_UPDATE_COMPANY_ECONOMY + - ADMIN_UPDATE_COMPANY_STATS + - ADMIN_UPDATE_CMD_NAMES + + ADMIN_UPDATE_CLIENT_INFO and ADMIN_UPDATE_COMPANY_INFO accept an additional + parameter. This parameter is used to specify a certain client or company. + Setting this parameter to UINT32_MAX (0xFFFFFFFF) will tell the server you + want to receive updates for all clients or companies. + + Not supported AdminUpdateType in the poll will result in the server + disconnecting the application with NETWORK_ERROR_ILLEGAL_PACKET. + + Additional debug information can be found with a debug level of net=3. + + +4.0) Sending rcon commands +---- --------------------- + Rcon runs separate from the ADMIN_UPDATE_CONSOLE AdminUpdateType. Requesting + the execution of a remote console command is done with the packet + ADMIN_PACKET_ADMIN_RCON. + + Note: No additional authentication is required for rcon commands. + + The server will reply with one or more ADMIN_PACKET_SERVER_RCON packets. + Finally an ADMIN_PACKET_ADMIN_RCON_END packet will be sent. Applications + will not receive the answer twice if they have asked for the AdminUpdateType + ADMIN_UPDATE_CONSOLE, as the result is not printed on the servers console + (just like clients rcon commands). + + Furthermore, sending a 'say' command (or any similar command) will not + be sent back into the admin network. + Chat from the server itself will only be sent to the admin network when it + was not sent from the admin network. + + Note that when content is queried or updated via rcon, the processing + happens asynchronously. But the ADMIN_PACKET_ADMIN_RCON_END packet is sent + already right after the content is requested as there's no immediate output. + Thus other packages and the output of content rcon command may be sent at + an arbitrary later time, mixing into the output of other console activity, + e.g. also of possible subsequent other rcon commands sent. + + +5.0) Sending chat +---- ------------ + Sending a ADMIN_PACKET_ADMIN_CHAT results in chat originating from the server. + + Currently four types of chat are supported: + - NETWORK_ACTION_CHAT + - NETWORK_ACTION_CHAT_CLIENT + - NETWORK_ACTION_CHAT_COMPANY + - NETWORK_ACTION_SERVER_MESSAGE + + NETWORK_ACTION_SERVER_MESSAGE can be sent to a single client or company + using the respective DestType and ID. + This is a message prefixed with the 3 stars, e.g. *** foo has joined the game + +5.1) Receiving chat +---- ------------- + Register ADMIN_UPDATE_CHAT at ADMIN_FREQUENCY_AUTOMATIC to receive chat. + The application will be able to receive all chat the server can see. + + The configuration option network.server_admin_chat specifies whether + private chat for to the server is distributed into the admin network. + + +6.0) Disconnecting +---- ------------- + It is a kind thing to say good bye before leaving. Do this by sending the + ADMIN_PACKET_ADMIN_QUIT packet. + + +7.0) Certain packet information +---- -------------------------- + All ADMIN_PACKET_SERVER_* packets have an enum value greater 100. + + ADMIN_PACKET_SERVER_WELCOME + Either directly follows ADMIN_PACKET_SERVER_PROTOCOL or is sent + after a new game has been started or a map loaded, i.e. also + after ADMIN_PACKET_SERVER_NEWGAME. + + ADMIN_PACKET_SERVER_CLIENT_JOIN and ADMIN_PACKET_SERVER_COMPANY_NEW + These packets directly follow their respective INFO packets. If you receive + a CLIENT_JOIN / COMPANY_NEW packet without having received the INFO packet + it may be a good idea to POLL for the specific ID. + + ADMIN_PACKET_SERVER_CMD_NAMES and ADMIN_PACKET_SERVER_CMD_LOGGING + Data provided with these packets is not stable and will not be + treated as such. Do not rely on IDs or names to be constant + across different versions / revisions of OpenTTD. + Data provided in this packet is for logging purposes only. diff --git a/docs/desync.txt b/docs/desync.txt new file mode 100644 index 0000000..b0b6bd7 --- /dev/null +++ b/docs/desync.txt @@ -0,0 +1,268 @@ +Some explanations about Desyncs +Last updated: 2014-02-23 +------------------------------------------------------------------------ + + +Table of contents +----------------- +1.0) Desync theory + * 1.1) OpenTTD multiplayer architecture + * 1.2) What is a Desync and how is it detected + * 1.3) Typical causes of Desyncs +2.0) What to do in case of a Desync + * 2.1) Cache debugging + * 2.2) Desync recording +3.0) Evaluating the Desync records + * 3.1) Replaying + * 3.2) Evaluation the replay + * 3.3) Comparing savegames + + +1.1) OpenTTD multiplayer architecture +---- -------------------------------- + OpenTTD has a huge gamestate, which changes all of the time. + The savegame contains the complete gamestate at a specific point + in time. But this state changes completely each tick: Vehicles move + and trees grow. + + However, most of these changes in the gamestate are deterministic: + Without a player interfering a vehicle follows its orders always + in the same way, and trees always grow the same. + + In OpenTTD multiplayer synchronisation works by creating a savegame + when clients join, and then transfering that savegame to the client, + so it has the complete gamestate at a fixed point in time. + + Afterwards clients only receive 'commands', that is: Stuff which is + not predictable, like + - player actions + - AI actions + - GameScript actions + - Admin Port command + - rcon commands + - ... + + These commands contain the information on how to execute the command, + and when to execute it. Time is measured in 'network frames'. + Mind that network frames to not match ingame time. Network frames + also run while the game is paused, to give a defined behaviour to + stuff that is executing while the game is paused. + + The deterministic part of the gamestate is run by the clients on + their own. All they get from the server is the instruction to + run the gamestate up to a certain network time, which basically + says that there are no commands scheduled in that time. + + When a client (which includes the server itself) wants to execute + a command (i.e. a non-predictable action), it does this by + - calling DoCommandP resp. DoCommandPInternal + - These functions first do a local test-run of the command to + check simple preconditions. (Just to give the client an + immediate response without bothering the server and waiting for + the response.) The test-run may not actually change the + gamestate, all changes must be discarded. + - If the local test-run succeeds the command is sent to the server. + - The server inserts the command into the command queue, which + assigns a network frame to the commands, i.e. when it shall be + executed on all clients. + - Enhanced with this specific timestamp, the command is send to all + clients, which execute the command simultaneously in the same + network frame in the same order. + +1.2) What is a Desync and how is it detected +---- --------------------------------------- + In the ideal case all clients have the same gamestate as the server + and run in sync. That is, vehicle movement is the same on all + clients, and commands are executed the same everywhere and + have the same results. + + When a Desync happens, it means that the gamestates on the clients + (including the server) are no longer the same. Just imagine + that a vehicle picks the left line instead of the right line at + a junction on one client. + + The important thing here is, that noone notices when a Desync + occurs. The desync client will continue to simulate the gamestate + and execute commands from the server. Once the gamestate differs + it will increasingly spiral out of control: If a vehicle picks a + different route, it will arrive at a different time at a station, + which will load different cargo, which causes other vehicles to + load other stuff, which causes industries to notice different + servicing, which causes industries to change production, ... + the client could run all day in a different universe. + + To limit how long a Desync can remain unnoticed, the server + transfers some checksums every now and then for the gamestate. + Currently this checksum is the state of the random number + generator of the game logic. A lot of things in OpenTTD depend + on the RNG, and if the gamestate differs, it is likely that the + RNG is called at different times, and the state differs when + checked. + + The clients compare this 'checksum' with the checksum of their + own gamestate at the specific network frame. If they differ, + the client disconnects with a Desync error. + + The important thing here is: The detection of the Desync is + only an ultimate failure detection. It does not give any + indication on when the Desync happened. The Desync may after + all have occurred long ago, and just did not affect the checksum + up to now. The checksum may have matched 10 times or more + since the Desync happend, and only now the Desync has spiraled + enough to finally affect the checksum. (There was once a desync + which was only noticed by the checksum after 20 game years.) + +1.3) Typical causes of Desyncs +---- ------------------------- + Desyncs can be caused by the following scenarios: + - The savegame does not describe the complete gamestate. + - Some information which affects the progression of the + gamestate is not saved in the savegame. + - Some information which affects the progression of the + gamestate is not loaded from the savegame. + This includes the case that something is not completely + reset before loading the savegame, so data from the + previous game is carried over to the new one. + - The gamestate does not behave deterministic. + - Cache mismatch: The game logic depends on some cached + values, which are not invalidated properly. This is + the usual case for NewGRF-specific Desyncs. + - Undefined behaviour: The game logic performs multiple + things in an undefined order or with an undefined + result. E.g. when sorting something with a key while + some keys are equal. Or some computation that depends + on the CPU architecture (32/64 bit, little/big endian). + - The gamestate is modified when it shall not be modified. + - The test-run of a command alters the gamestate. + - The gamestate is altered by a player or script without + using commands. + + +2.1) Cache debugging +---- --------------- + Desyncs which are caused by inproper cache validation can + often be found by enabling cache validation: + - Start OpenTTD with '-d desync=2'. + - This will enable validation of caches every tick. + That is, cached values are recomputed every tick and compared + to the cached value. + - Differences are logged to 'commands-out.log' in the autosave + folder. + + Mind that this type of debugging can also be done in singleplayer. + +2.2) Desync recording +---- ---------------- + If you have a server, which happens to encounter Desyncs often, + you can enable recording of the gamestate alterations. This + will later allow the replay the gamestate and locate the Desync + cause. + + There are two levels of Desync recording, which are enabled + via '-d desync=2' resp. '-d desync=3'. Both will record all + commands to a file 'commands-out.log' in the autosave folder. + + If you have the savegame from the start of the server, and + this command log you can replay the whole game. (see Section 3.1) + + If you do not start the server from a savegame, there will + also be a savegame created just after a map has been generated. + The savegame will be named 'dmp_cmds_*.sav' and be put into + the autosave folder. + + In addition to that '-d desync=3' also creates regular savegames + at defined spots in network time. (more defined than regular + autosaves). These will be created in the autosave folder + and will also be named 'dmp_cmds_*.sav'. + + These saves allow comparing the gamestate with the original + gamestate during replaying, and thus greatly help debugging. + However, they also take a lot of disk space. + + +3.1) Replaying +---- --------- + To replay a Desync recording, you need these files: + - The savegame from when the server was started, resp. + the automatically created savegame from when the map + was generated. + - The 'commands-out.log' file. + - Optionally the 'dmp_cmds_*.sav'. + Put these files into a safe spot. (Not your autosave folder!) + + Next, prepare your OpenTTD for replaying: + - Get the same version of OpenTTD as the original server was running. + - Uncomment/enable the define 'DEBUG_DUMP_COMMANDS' in + 'src/network/network_func.h'. + (DEBUG_FAILED_DUMP_COMMANDS is explained later) + - Put the 'commands-out.log' into the root save folder, and rename + it to 'commands.log'. + - Run 'openttd -D -d desync=3 -g startsavegame.sav'. + This replays the server log and creates new 'commands-out.log' + and 'dmp_cmds_*.sav' in your autosave folder. + +3.2) Evaluation the replay +---- --------------------- + The replaying will also compare the checksums which are part of + the 'commands-out.log' with the replayed gamestate. + If they differ, it will trigger a 'NOT_REACHED'. + + If the replay succeeds without mismatch, that is the replay reproduces + the original server state: + - Repeat the replay starting from incrementally later 'dmp_cmds_*.sav' + while truncating the 'commands.log' at the beginning appropriately. + The 'dmp_cmds_*.sav' can be your own ones from the first reply, or + the ones from the original server (if you have them). + (This simulates the view of joining clients during the game.) + - If one of those replays fails, you have located the Desync between + the last dmp_cmds that reproduces the replay and the first one + that fails. + + If the replay does not succeed without mismatch, you can check the logs + whether there were failed commands. Then you may try to replay with + DEBUG_FAILED_DUMP_COMMANDS enabled. If the replay then fails, the + command test-run of the failed command modified the game state. + + If you have the original 'dmp_cmds_*.sav', you can also compare those + savegames with your own ones from the replay. You can also comment/disable + the 'NOT_REACHED' mentioned above, to get another 'dmp_cmds_*.sav' from + the replay after the mismatch has already been detected. + See Section 3.2 on how to compare savegames. + If the saves differ you have located the Desync between the last dmp_cmds + that match and the first one that does not. The difference of the saves + may point you in the direction of what causes it. + + If the replay succeeds without mismatch, and you do not have any + 'dmp_cmd_*.sav' from the original server, it is a lost case. + Enable creation of the 'dmp_cmd_*.sav' on the server, and wait for the + next Desync. + + Finally, you can also compare the 'commands-out.log' from the original + server with the one from the replay. They will differ in stuff like + dates, and the original log will contain the chat, but otherwise they + should match. + +3.2) Comparing savegames +---- ------------------- + The binary form of the savegames from the original server and from + your replay will always differ: + - The savegame contains paths to used NewGRF files. + - The gamelog will log your loading of the savegame. + - The savegame data of AIs and the Gamescript will differ. + Scripts are not run during the replay, only their recorded commands + are replayed. Their internal state will thus not change in the + replay and will differ. + + To compare savegame more semantically, there exist some ugly hackish + tools at: + http://devs.openttd.org/~frosch/texts/zpipe.c + http://devs.openttd.org/~frosch/texts/printhunk.c + + The first one decompresses OpenTTD savegames. The second one creates + a textual representation of an uncompressed savegame, by parsing hunks + and arrays and such. With both tools you need to be a bit careful + since they work on stdin and stdout, which may not deal well with + binary data. + + If you have the textual representation of the savegames, you can + compare them with regular diff tools. diff --git a/docs/elrail.svg b/docs/elrail.svg new file mode 100644 index 0000000..39098a3 --- /dev/null +++ b/docs/elrail.svg @@ -0,0 +1,1091 @@ + + + + + + + + + image/svg+xml + + + + + + + + N + + Pylon Control Point (PCP) + + + + + + + + + + + + + + + + not allowed, not owned + not allowed, owned + allowed, owned + allowed, not owned + Pylon Position Point (PPP) + + + + + + + + + + + + + + + + + + + + + + + + + + + + not allowed, but preferred (end of line marker) + not allowed + preferred, allowed + allowed + Pylon Position Point (PPP) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + preferred, allowed andcan be ignored to createlong wires (which span2 tiles) + + diff --git a/docs/elrail_tile.png b/docs/elrail_tile.png new file mode 100644 index 0000000..bcbcea5 Binary files /dev/null and b/docs/elrail_tile.png differ diff --git a/docs/elrail_track.png b/docs/elrail_track.png new file mode 100644 index 0000000..a27276b Binary files /dev/null and b/docs/elrail_track.png differ diff --git a/docs/landscape.html b/docs/landscape.html new file mode 100644 index 0000000..f60e859 --- /dev/null +++ b/docs/landscape.html @@ -0,0 +1,1619 @@ + + + + + + + + OpenTTD Landscape Internals + + + + +

Landscape

+

+ For a graphical representation of the tile-layout have a look at + Landscape grid page. +

+

Nine attributes (counting "type" and + "height") hold the informations about a tile.
+ These attributes are referred to as + "type", + "height", + "m1", "m2", + "m3", "m4", + "m5", "m6" + and "m7".
+ The most important value is the class of a tile, stored in the upper 4 bits + of the type attribute. +

+ + Frequently repeating patterns: +
    +
  • type +
      +
    • + + Bits 7..4: + + + + + + + + + + + + + +
      The tile type.
      00Ground
      01Railway tracks
      02Roads
      03Town building
      04Trees
      05Station tiles
      06Water
      07Void
      08Industries
      09Tunnel / bridge
      0AObjects
      +
    • + Bits 3..2: + + + + + +
      Presence and direction of bridge above.
      00no bridge
      01Axis X (North-East)
      02Axis Y (South-West)
      +
    • + + Bits 1..0: + + + + + +
      Only meaningfull in tropic climate. It contains the definition of the available zones
      00normal
      01desert
      02rain forest
      + In any other climate these 2 bits are theoretically free of use, however using them does not seem useful. +
    • +
    +
  • m1 +
      +
    • + + Bits 6..5: + + + + + +
      The type of water that is on a tile. +
      00Sea
      01Canal
      02River
      03Invalid, i.e. no water on this tile
      + Some tiles, such as houses, reuse these bits of other purposes. +
    • +
    • + + Bits 4..0: + + + + + + +
      The owner of a tile can be either companies (human or AI) or "Game entities". +
      00..0ENormal companies
      0Fa town owns the tile
      10nobody owns the tile
      11"water" owns the tile
      FFspectator in MP or in scenario editor
      + Some tiles, such as houses and industries, reuse these bits of other purposes. +
    • +
    +
  • +
  • m7:
    + Animation frame/state. Used for houses, industries, objects and stations. +
  • +
+ +

OTTD's class-specific periodic tile processing routine is called once every +256 ticks for each tile.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ClassMeaning & details of encoding
0  Ground
  +
    +
  • m1 bits 4..0: owner of the tile (normally 10)
  • +
  • m2: see fields
  • +
  • m3 bits 7..5: type of hedge on NE border of the tile
  • +
  • m3 bits 3..0: see fields
  • +
  • m3 bit 4: set if the tile is covered with snow
  • +
  • m4 bits 7..5: type of hedge on the SW border of the tile (1 through 6, or 0=none)
  • +
  • m4 bits 4..2: same as 7..5, but for the SE border
  • +
  • m5 bits 7..5: update counter, incremented on every periodic processing for tile types, + other than 03, 07, 0B, 10 and above.
    + on wraparound, the tile is updated (for fields, the type of fields in m3 is increased, for other types the tile type in m5 is increased).
    + For snow and desert, these bits are not used, tile is updated on every periodic processing.
  • +
  • m5 bits 4..2: tile type: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    0  bare land / grass
    1  rough land (density must be 3)
    2  rocks (density must be 3)
    3  fields (density must be 3) +
      +
    • m2: index into the array of industries (farms), INVALID_INDUSTRY (0xFFFF) if farm has been removed
    • +
    • m3 bits 3..0: field type (legal values: 0 through 9)
    • +
    +
    4  snow
    5  desert (density must be 1 or 3)
    +
  • +
  • m5 bits 1..0: density: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    0  bare land1/4 snow
    1  1/3 grass2/4 snow; 1/2 desert
    2  2/3 grass3/4 snow
    3  full grass; rough land; rocks; fields; full snow; full desert
    +
  • +
  • m6 bits 4..2: type of hedge on NW border of the tile
  • +
+
1Railway tracks
  +
    +
  • m1 bits 4..0: owner of the tile
  • +
  • m2: see signals
  • +
  • m3 bits 7..4: see signals
  • +
  • m3 bits 3..0 = track type: + + + + + + + + + + + + + + + + + + + + +
    0  conventional railway
    1  electrified railway
    2  monorail
    3  maglev
    +
  • +
  • m4 bits 7..4: see signals
  • +
  • m4 bits 3..0: Ground type (values with fences are not valid for depots and checkpoints) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    0  on bare land
    1  on grass, no fences
    2  fence on the NW side
    3  fence on the SE side
    4  fences on the NW and SE sides
    5  fence on the NE side
    6  fence on the SW side
    7  fences on the NE and SW sides
    8  fence on the E side (track in the W corner)
    9  fence on the W side (track in the E corner)
    A  fence on the S side (track in the N corner)
    B  fence on the N side (track in the S corner)
    C  on snow or desert
    D  on grass with fence and shore or water on the free halftile
    E  higher part on foundation with snow, lower without snow
    +
  • +
  • m5 bit 7 clear: railway track +
      +
    • m5 bits 5..0: track layout: bit set = track present: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      bit 0: in the X direction
      bit 1: in the Y direction
      bit 2: in the north corner (direction W-E)
      bit 3: in the south corner (direction W-E)
      bit 4: in the west corner (direction N-S)
      bit 5: in the east corner (direction N-S)
      +
    • +
    • m5 bit 6 set = with signals:
      + There are at most 4 signals on a tile. The signals 0..3 belong to the directions: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Track 0 (X) Track 1 (Y) Track 2 (north) Track 3 (south) Track 4 (west) Track 5 (east)
      Signal 0 westsouth
      Signal 1 eastnorth
      Signal 2 south-westnorth-westwestsouth
      Signal 3 north-eastsouth-easteastnorth
      +
        +
      • m2 bit 7: Signal 0 and 1: set = semaphore signals, clear = light signals
      • +
      • m2 bit 3: Signal 2 and 3: set = semaphore signals, clear = light signals
      • +
      • m2 bits 6..4: type of signal 0 and 1 (same values as m2 bits 2..0)
      • +
      • m2 bits 2..0: type of signal 2 and 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        000: normal signals
        001: pre-signals
        010: exit-signals
        011: combo-signals
        100: pbs signals
        101: no-entry signals
        +
      • + +
      • m3 bits 7..4: bit set = signal 3..0 present
      • +
      • m4 bits 7..4: bit clear = signal 3..0 shows red
      • +
      +
    • +
    • m2 bits 8..10: track reserved for pbs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      0  not reserved
      1  X direction
      2  Y direction
      3  north corner (W-E)
      4  south corner (W-E)
      5  west corner (N-S)
      6  east corner (N-S)
      +
    • +
    • m2 bit 11: opposite track is reserved, too
    • +
    +
  • +
  • m5 bit 7 set, bit 6 set: railway depot +
      +
    • m2: Depot index
    • +
    • m5 bits 1..0: exit towards + + + + + + + + + + + + + + + + + + + + +
      0  NE
      1  SE
      2  SW
      3  NW
      +
    • +
    • m5 bit 4: pbs reservation state
    • +
    +
  • +
+
2Roads
  +
    +
  • m2: Index into the array of towns (owning town for town roads; closest town otherwise, INVALID_TOWN if there is no town or we are creating a town)
  • +
  • m7 bit 5 set = on snow or desert
  • +
  • m7 bits 7..6: present road types + + + + + + + + + + +
    bit 0  normal road
    bit 1  tram
    +
  • +
  • m3 bits 7..4: owner of road type 1 (tram); OWNER_NONE (10) is stored as OWNER_TOWN (0F) +
  • m5 bits 7 clear: road or level-crossing +
      +
    • m6 bits 5..3: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      0  on bare land
      1  on grass
      2  paved
      3  with streetlights
      5  tree-lined
      6  on grass with road works
      7  paved with road works
      +
    • +
    • m5 bit 6 clear: road +
        +
      • m1 bits 4..0: owner of the road type 0 (normal road)
      • +
      • m7 bits 3..0: counter for the roadworks
      • +
      • m5 bits 3..0: road layout road type 0 (normal road): bit set = road piece present: + + + + + + + + + + + + + + + + + +
        bit 0: NW piece
        bit 1: SW piece
        bit 2: SE piece
        bit 3: NE piece
        +
      • +
      • m3 bits 0..3: road layout road type 1 (tram)
      • +
      • m5 bits 5..4: bits to disallow vehicles to go a specific direction + + + + + + + + + +
        bit 0: set = disallow driving in south-west or south-east direction
        bit 1: set = disallow driving in north-west or north-east direction
        +
      • +
      +
    • +
    • m5 bit 6 set: level crossing +
        +
      • m1 bits 4..0: owner of the railway track
      • +
      • m3 bits 3..0: railway track type
      • +
      • m5 bit 0: direction + + + + + + + + + +
        0  road in the X direction, rail in Y
        1  road in the Y direction, rail in X
        +
      • +
      • m5 bit 5: set if crossing lights are on
      • +
      • m7 bits 4..0: owner of the road type 0 (normal road)
      • +
      • m5 bit 4: pbs reservation state
      • +
      +
    • +
    +
  • +
  • m5 bit 7 set, bit 6 clear: road depot +
      +
    • m1 bits 4..0: owner of the depot
    • +
    • m2: Depot index
    • +
    • m5 bits 1..0: exit towards: + + + + + + + + + + + + + + + + + + + + +
      0  NE
      1  SE
      2  SW
      3  NW
      +
    • +
    • m7 bits 4..0: owner of the road type 0 (normal road)
    • +
    +
  • +
+
3Town building
  +
    +
  • m1 : Random bits (newhouses)
  • +
  • m2 : index into the array of towns
  • +
  • m3 bit 7 : +
      +
    • set : House is complete +
        +
      • m5 : Age of house in years, clamped at 255
      • +
      +
    • +
    • clear : House is in construction +
        +
      • m5 bits 7..5 : free
      • +
      • m5 bits 4..3 : construction stage
      • +
      • m5 bits 2..0 : construction counter
      • +
      +
    • +
    +
  • m3 bit 6 : bit 8 of house type (m4), allowing 512 different types.
  • +
  • m3 bit 5 : free
  • +
  • m3 bits 4..0 : triggers activated (newhouses)
  • +
  • m4 : town building type (with m3[6] bit)
  • +
  • m5 : see m3 bit 7
  • +
  • m6 : +
      +
    • If newhouses is activated +
        +
      • bits 7..2 : Periodic processing time remaining
      • +
      +
    • +
    • Standard behaviour +
        +
      • bits 7..2 : lift position (for houses type 04 and 05)
      • +
      +
    • +
    +
  • +
  • m7 : +
      +
    • If newhouses is activated +
        +
      • Current animation frame
      • +
      +
    • +
    • Standard behaviour (only for houses type 04 and 05) +
        +
      • bits 7..4 : free
      • +
      • bits 3..1 : lift destination. Values can be 0..6, except 1.
        + So the building has 6 effective floors. This is due to the fact that the first floor is 2 'normal' floors high.
        + One 'normal' floor has a height of 6 lift positions. +
      • +
      • bit 0 : Lift has destination when set
      • +
      +
    • +
    +
  • +
+ Newhouses is the name englobing a newGRF feature developped by TTDPatch devs (mainly Csaboka).
+ It allows the replacement of the properties as well as the graphics of houses in the game.
+ To distinguish between the standard behaviour and the newGRF one, HouseID (m4 + m3[6]) is tested for anything above 110.
+ 110 is the count of standard houses. So above 110 means there is a new definition of at least one house
+
4 Trees
  +
    +
  • m1 bits 4..0: owner (normally 10)
  • +
  • m2 bits 8..6: ground + + + + + + + + + + + + + + + + + + + + + + + + + + +
    0  on grass
    1  on rough land (density must be 3)
    2  on snow or desert
    3  on shore (density must be 3)
    4  on snow with rough land underneed
    +
  • +
  • m2 bits 5..4: ground density
  • +
  • m2 bits 3..0: update counter, incremented on every periodic processing.
    + on wraparound the growth status is updated (or, if it's 3, a random action is taken)
  • +
  • m3 bits 7..0: type of trees: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    00..0B  temperate climate trees
    0C..13  sub-arctic climate trees
    14..1A  rainforest trees
    1B cactus plants
    1C..1F  sub-tropical climate, non-rainforest, non-desert trees
    20..28  toyland trees
    + Note: the actually displayed set of trees depends on both type and number of trees +
  • +
  • m5 bits 7..6: number of trees minus one
  • +
  • m5 bits 2..0: growth status: + + + + + + + + + + + + + +
    0..2 one of trees is growing 
    3 all trees are fully grown 
    4..6 one of trees is withering 
    +
  • +
+
5Station tiles
  +
    +
  • m1 bits 6..5: water class for buoys, water part of docks and for airport tiles
  • +
  • m1 bits 4..0: owner of the station
  • +
  • m2: index into the array of stations
  • +
  • m3 bits 7..4: persistent random data for railway stations/waypoints and airports)
  • +
  • m3 bits 7..4: owner of tram tracks (road stop)
  • +
  • m3 bits 3..0: track type for railway stations/waypoints
  • +
  • m4: custom station id; 0 means standard graphics
  • +
  • m5: graphics index (range from 0..255 for each station type): + + + + + + + + + + + + + + + + + + + + + + + + + +
    00..07  railway station + + + + + + + + + + + + + + + + +
    00..01  open platform
    02..03  open platform with station building
    04....07  roofed platform
    bit 0: clear = in X direction, set = in Y direction
    +
    00..01waypoints + + + + + + + + + +
    00  in X direction
    01  in Y direction
    +
    00..FFall airports
    00..05  road stops + + + + + + + + + + + + + + + + + + + + + + + + + +
    00  exit towards NE
    01  exit towards SE
    02  exit towards SW
    03  exit towards NW
    04  drive through X
    05  drive through Y
    +
    00..05  ship dock + + + + + + + + + + + + + + + + + + + + + + + + + +
    00  SW coast part
    01  NW coast part
    02  NE coast part
    03  SE coast part
    04  X direction water part
    05  Y direction water part
    +
    +
  • +
  • m6 bits 5..3: the station type (rail, airport, truck, bus, oilrig, dock, buoy, waypoint)
  • +
  • m6 bit 2: pbs reservation state for railway stations/waypoints
  • + +
  • m7 bits 4..0: owner of road (road stops)
  • +
  • m7 bits 7..6: present road types (road stops)
  • +
  • m7: animation frame (railway stations/waypoints, airports)
  • +
+
6 Water
  +
    +
  • m1 bits 6..5 : Water class (sea, canal or river) +
  • m1 bits 4..0: owner (for sea, rivers, and coasts normally 11)
  • +
  • m2: Depot index (for depots only)
  • +
  • m4: Random data for canal or river tiles
  • +
  • m5: tile type: + + + + + + + + + + + + + + + + + + + + +
    00  water, canal or river
    01  coast or riverbank
    10..1B  canal locks + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    10  middle part, (SW-NE direction)
    11  middle part, (NW-SE direction)
    12  middle part, (NE-SW direction)
    13  middle part, (SE-NW direction)
    14  lower part, (SW-NE direction)
    15  lower part, (NW-SE direction)
    16  lower part, (NE-SW direction)
    17  lower part, (SE-NW direction)
    18  upper part, (SW-NE direction)
    19  upper part, (NW-SE direction)
    1A  upper part, (NE-SW direction)
    1B  upper part, (SE-NW direction)
    +
    80..83  ship depots + + + + + + + + + + + + + + + + + +
    80  ship depot, NE part (X direction)
    81  ship depot, SW part (X direction)
    82  ship depot, NW part (Y direction)
    83  ship depot, SE part (Y direction)
    +
    +
  • +
+
7 Void
 Tiles of this class form an invisible, one tile wide border at the south (bottom) edges of the map,
+ so as to protect several algorithms from the consequences of a wraparound at the edges. +
8Industries
  +
    +
  • m1 bit 7: clear = under construction +
      +
    • m1 bits 6..5 : Water class (sea, canal, river or land) +
    • m1 bits 3..2: construction counter, for buildings under construction incremented on every periodic tile processing
    • +
    • m1 bits 1..0: stage of construction (3 = completed), incremented when the construction counter wraps around
      + the meaning is different for some animated tiles which are never under construction (types 01, 1E..20, 30, 58; see above)
    • +
    +
  • +
  • m2: index into the array of industries
  • +
  • m3: random bits (NewGRF)
  • +
  • m4: animation loop
  • +
  • m5: type (plus m6 bit 2):
    + (note: this is not the same as the industry type, which is stored in the array of industries) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    00..06  coal mine + + + + + + + + + +
    00  wheel tower when not animated
    01  wheel tower when animated
    + animation state in m7 bits 5..0; m7 bit 6 set = sound already generated
    +
    07..0A  power station + + + + + + + + + +
    08  chimney
    0A  transformer; animation progress in m7(valid range 0..7)
    +
    0B..0F  sawmill
    10..11  forest + + + + + +
    11  trees cut down
    +
    12..17  oil refinery
    18..1C  oil rig
    1D..20  oil wells + + + + + + + + + +
    1D  not animated
    1E..20  various stages of animation; progress of animation in m7
    +
    21..26  farm
    27..2A  factory (temperate climate)
    2B..2E  printing works
    2F..33  copper ore mine + + + + + + + + + + + + + +
    2F  wheel tower when not animated
    30  wheel tower when animated; animation state in m7 bits 5..0; m7 bit 6 set = sound already generated
    31  chimney
    +
    34..39  steel mill
    3A..3B  bank (temperate climate)
    3C..3F  food processing plant
    40..47  paper mill
    48..58  gold mine + + + + + + + + + +
    4F  wheel tower when not animated
    58  wheel tower when animated; animation state in m7 bits 5..0; m7 bit 6 set = sound already generated
    59..5A  bank (sub-arctic or sub-tropical climate)
    5B..63  diamond mine
    64..73  iron ore mine
    74fruit plantation
    75rubber plantation
    76..77  water supply
    78water tower
    79..7C  factory (sub-tropical climate)
    7D..80  lumber mill
    81..82  candyfloss forest + + + + + +
    82  candyfloss 'trees' cut down
    +
    83..86  sweet factory
    87..88  battery farm + + + + + +
    88  batteries 'reaped'
    +
    89cola wells
    8A..8D  toy shop
    8E..93  toy factory + + + + + +
    8F  Animated part; animation state in m7 (valid range 00..31)
    + Tile animation is started (m4 zeroed) on the periodic processing.
    + While the animation is in progress, m4 holds the number + of animation cycles that have already taken place.
    + when this number reaches 8 the animation is stopped.
    +
    94..9B  plastic fountains (various stages of cyclic animation)
    9C..9F  fizzy drink factory
    A0..A3  bubble generator + + + + + + + + + +
    A1  generators
    A2  bubble capture facility; animation state in m7 (valid range 00..27)
    +
    A4..A6  toffee quarry + + + + + +
    A5  animated part; animation state in m3 (valid range 00..45)
    +
    A7..AE  sugar mine + + + + + +
    AE  animated part; animation state in m3 (valid range 00..5F)
    +
    AF..1FF  NewGRF industries industry
    +
  • +
  • m6 bits 5..3: random triggers (NewGRF)
  • +
  • m6 bit 2: bit 8 of type (see m5)
  • +
  • m7: animation frame
  • +
+
9Tunnel / bridge
  +
    +
  • m1 bits 4..0: owner
  • +
  • m3 bits 7..4: owner of tram
  • +
  • m3 bits 3..0: track type for railway
  • +
  • m5 bit 4: pbs reservation state for railway
  • +
  • m5 bits 7 clear: tunnel entrance/exit
  • +
  • m5 bit 7 set: bridge ramp +
      +
    • m6 bits 5..2: bridge type: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Type Max. speed (mph) Description
      0  20wooden
      1  30concrete
      2  40girder, steel
      3  50suspension, concrete
      4  60suspension, steel
      5  70suspension, steel
      6  100cantilever, steel
      7  130cantilever, steel
      8  150cantilever, steel
      9  160girder, steel
      A  200tubular, steel
      B  320tubular, steel
      C  380tubular, silicon
      +
    • +
    +
  • +
  • m5 bits 3..2: transport type + + + + + + + + + + + + + + + +
    0 railway
    1 road
    2 water
    +
  • +
  • m5 bits 1..0: direction onto the bridge / out of the tunnel + + + + + + + + + + + + + + + + + + + + +
    0  NE
    1  SE
    2  SW
    3  NW
    +
  • +
  • m7 bits 4..0: owner of road
  • +
  • m7 bit 5 set = on snow or desert
  • +
  • m7 bits 7..6: present road types for road
  • +
+
AObjects
  +
    +
  • m1 bits 6..5 : Water class (sea, canal, river or land)
  • +
  • m1 bits 4..0: owner of the object (for lighthouses and transmitters normally 10)
  • +
  • m2: index into the array of objects, bits 0 to 15 (upper bits in m5)
  • +
  • m3: random bits
  • +
  • m5: index into the array of objects, bits 16 to 23 (lower bits in m2)
  • +
  • m7: animation counter
  • +
+
Classes B through F are reserved. The presence + of a tile in one of the reserved classes will crash OTTD.
+ + +
+ Original Copyright © 2003 by Marcin Grzegorczyk for TTDLX.
+ Transport Tycoon and Transport Tycoon Deluxe are Copyright © by Chris Sawyer.
+ All the other trademarks are the property of their respective owners.
+ + + diff --git a/docs/landscape_externals.html b/docs/landscape_externals.html new file mode 100644 index 0000000..cef6c2f --- /dev/null +++ b/docs/landscape_externals.html @@ -0,0 +1,616 @@ + + + + + + + + OpenTTD Landscape externals + + + +

Landscape

+

+ These are the different house types available on standard game.
+ Note: In the climate list, 'sub-arctic' means below the snow line, and 'snow' means above the snow line in the sub-arctic climate. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Type Size Climates Description
00  1×1temperatetall office block
01  1×1temperateoffice block
02  1×1temperatesmall block of flats
03  1×1temperatechurch
04  1×1temperate, sub-arctic, sub-tropicallarge office block
05  1×1snowlarge office block
06  1×1temperatetown houses
07..08  1×2temperatehotel
09  1×1temperate, sub-arctic, sub-tropical  statue
0A  1×1temperate, sub-arctic, sub-tropicalfountain
0B  1×1temperatepark (with a pond)
0C  1×1temperatepark (with an alley)
0D  1×1temperateoffice block
0E..10  1×1temperatevarious types of shops and offices
11  1×1temperate, sub-arctic, sub-tropicalmodern office building
12  1×1temperatewarehouse
13  1×1temperateoffice block (with spiral stairway on the side)
14..17  2×2temperatestadium
18  1×1temperateold houses
19  1×1temperatecottages
1A  1×1temperatehouses
1B  1×1temperateflats
1C  1×1temperatetall office block
1D  1×1temperateshops and offices
1E  1×1temperate, sub-tropicalshops and offices
1F  1×1temperatetheatre
20..23  2×2temperate, sub-arctic, sub-tropicalstadium (modern style)
24  1×1temperate, sub-arctic, sub-tropicaloffices (the modern 'vertical tube' style)
25  1×1sub-arctichouses
26  1×1snowhouses
27  1×1temperatecinema
28..2B  2×2temperateshopping mall
2C  1×1sub-arcticflats
2D  1×1snowflats
2E  1×1sub-arctichouses
2F  1×1snowhouses
30  1×1sub-arctichouses
31  1×1snowhouses
32  1×1sub-arctic, sub-tropicaltall office block
33  1×1snowtall office block
34  1×1sub-arctictall office block
35  1×1snowtall office block
36  1×1sub-arctic, sub-tropicaltall office block
37  1×1snowtall office block
38  1×1sub-arctichouses
39  1×1snowhouses
3A  1×1sub-arcticshops and offices
3B  1×1snowshops and offices
3C  1×1sub-arcticchurch
3D  1×1snowchurch
3E  1×1sub-arctichouses
3F  1×1snowhouses
40  1×1sub-arcticshops and offices
41  1×1snowshops and offices
42..43  1×2sub-arctichotel
44..45  1×2snowhotel
46  1×1sub-arctic, sub-tropicalshops and offices
47  1×1snowshops and offices
48  1×1sub-arctictall office block
49  1×1snowtall office block
4A..4B  2×1sub-arctictall office block
4C..4D  2×1snowtall office block
4E  1×1sub-tropicalhouses (with a tree in a corner)
4F, 50  1×1sub-tropicalhouses
51  1×1sub-tropicalhouses (suburb-type)
52  1×1sub-tropicalflats
53  1×1sub-tropicalchurch
54  1×1sub-tropicalhouses (with two trees in front)
55, 56  1×1sub-tropicalflats
57..58  2×1sub-tropicaltall office block
59  1×1sub-tropicalflats
5A  1×1sub-tropicaltall office block
5B  1×1toylandchurch
5C..61  1×1toylandvarious types of toyland houses
62  1×1toylandtall office block
63..64  1×2toylandhouses ('shoe' style)
65  1×1toylandtall office block
66  1×1toylandigloo
67  1×1toylandtepees
68, 69  1×1toylandshops and offices
6A  1×1toylandtall office block
6B  1×1toylandstatue
6C  1×1toylandteapot-house
6D  1×1toylandpiggy-bank
+ + + \ No newline at end of file diff --git a/docs/landscape_grid.html b/docs/landscape_grid.html new file mode 100644 index 0000000..98351fc --- /dev/null +++ b/docs/landscape_grid.html @@ -0,0 +1,370 @@ + + + + + + OpenTTD Landscape Internals - #2 + + + +

Landscape

+Six attributes hold the information about a tile. +This can be seen in the Landscape document. This page tries to give an overview of used and free bits of +the array so you can quickly see what is used and what is not. +
    +
  • O - bit is free
  • +
  • X - bit is used
  • +
  •   - bit of attribute is abused for different purposes, i.e. other bits define the actual meaning.
  • +
  • ~ - bit is accessed, but does not really have a meaning (e.g. owner of clear land is always OWNER_NONE)
  • +
+

+

    +
  • type - 8 bits in size, tile class (bits 4..7), bridge (bits 2..3) tropic zone (bits 0..1, only valid in tropic climate)
  • +
  • height - 8 bits in size, stores tile height
  • +
  • m1 - 8 bits in size, used to identify the owner of that tile (eg piece of rail, bridge, etc.)
  • +
  • m2 - 16 bits in size, used to identify the index of the given tile (object) in the (object-)array
  • +
  • m3 - 8 bits in size, is used for general storage
  • +
  • m4 - 8 bits in size, is used for general storage
  • +
  • m5 - 8 bits in size, is used for general storage
  • +
  • m6 - 8 bits in size, is used for general storage
  • +
  • m7 - 8 bits in size, is used for general storage
  • +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
classtype (8)height (8)m1 (8)m2 (16)m3 (8)m4 (8)m5 (8)m6 (8)m7 (8)
bits7654 32107654 32107654 3210FEDC BA98 7654 32107654 32107654 32107654 32107654 32107654 3210
0groundXXXX XXXXXXXX XXXXOOO~ ~~~~OOOO OOOO OOOO OOOOXXXX OOOOXXXX XXOOXXXX XXXXOOOX XXOOOOOO OOOO
farmland-inherit--inherit--inherit-XXXX XXXX XXXX XXXXXXXX XXXX-inherit--inherit-OOOX XXOOOOOO OOOO
1railXXXX XXXXXXXX XXXXOOOX XXXXOOOO XXXX OOOO OOOOOOOO XXXXOOOO XXXXXXXX XXXXOOOO OOOOOOOO OOOO
rail with signals-inherit--inherit--inherit-OOOO XXXX XXXX XXXXXXXX XXXXXXXX XXXX-inherit-OOOO OOOOOOOO OOOO
depot-inherit--inherit--inherit-XXXX XXXX XXXX XXXXOOOO XXXXOOOO XXXXXXOX OOXXOOOO OOOOOOOO OOOO
2roadXXXX XXXXXXXX XXXXOOOX XXXXXXXX XXXX XXXX XXXXXXXX XXXXOOOO OOOOXXXX XXXXOOXX XOOOXXXO XXXX
level crossing-inherit--inherit--inherit--inherit-XXXX XXXX-inherit-XXXX OOOXOOXX XOOOXXXX XXXX
road depot-inherit--inherit--inherit--inherit-XXXX OOOOOOOO OOOOXXOO OOXXOOOO OOOOXXXO XXXX
3houseXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXX XXXX XXXXXXO~ ~~XXXXXX XXXXXXXX XXXXXXXX XXOOXXXX XXXX
4treesXXXX XXXXXXXX XXXXOOO~ ~~~~OOOO OOOX XXXX XXXX~~XX XXXXOOOO OOOOXXOO OXXXOOOO OOOOOOOO OOOO
5rail stationXXXX XXXXXXXX XXXXOXXX XXXXXXXX XXXX XXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXOOXX XXOOXXXX XXXX
rail waypoint-inherit--inherit--inherit--inherit--inherit--inherit--inherit--inherit--inherit-
road stop-inherit--inherit--inherit--inherit-XXXX OOOOOOOO OOOO~~~~ ~XXXOOXX XOOOXXOX XXXX
dock-inherit--inherit--inherit--inherit-OOOO OOOOOOOO OOOO~~~~ ~XXXOOXX XOOOOOOO OOOO
airport-inherit--inherit--inherit--inherit-XXXX OOOOOOOO OOOOXXXX XXXXOOXX XOOOXXXX XXXX
buoy-inherit--inherit--inherit--inherit-OOOO OOOOOOOO OOOO~~~~ ~~~~OOXX XOOOOOOO OOOO
oilrig-inherit--inherit--inherit--inherit-OOOO OOOOOOOO OOOO~~~~ ~~~~OOXX XOOOOOOO OOOO
6sea, shoreXXXX XXXXXXXX XXXXOXXX XXXXOOOO OOOO OOOO OOOOOOOO OOOOOOOO OOOOX~~X XXXXOOOO OOOOOOOO OOOO
canal, river-inherit--inherit--inherit-OOOO OOOO OOOO OOOOOOOO OOOOXXXX XXXX-inherit-OOOO OOOOOOOO OOOO
shipdepot-inherit--inherit--inherit-XXXX XXXX XXXX XXXXOOOO OOOOOOOO OOOO-inherit-OOOO OOOOOOOO OOOO
8industryXXXX XXXXXXXX XXXXXXXO XXXXXXXX XXXX XXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXOOXX XXOOXXXX XXXX
9tunnel entranceXXXX XXXXXXXX XXXXOOOX XXXXOOOO OOOO OOOO OOOOXXXX XXXXOOOO OOOOXOOX XXXXOOOO OOOOXXXX XXXX
bridge ramp-inherit--inherit--inherit--inherit--inherit--inherit--inherit-OOXX XXOO-inherit-
AobjectsXXXX XXXXXXXX XXXXOXXX XXXXXXXX XXXX XXXX XXXXXXXX XXXXOOOO OOOOXXXX XXXXOOOO OOOOXXXX XXXX
+ + + diff --git a/docs/linkgraph.txt b/docs/linkgraph.txt new file mode 100644 index 0000000..2515185 --- /dev/null +++ b/docs/linkgraph.txt @@ -0,0 +1,30 @@ +Some clarifications about the link graph +---------------------------------------- + +InitializeLinkGraphs joins all threads, so if the game is abandoned +with some threads still running, they're joined as soon as the next game +(possibly the title game) is started. See also InitializeGame. + +The MCF (multi-commodity flow) algorithm can be quite CPU-hungry as it's +NP-hard and takes exponential time (though with a very small constant +factor) in the number of nodes. +This is why it is run in a separate thread where possible. However after +some time the thread is joined and if it hasn't finished by then the game +will hang. This problem gets worse if we are running on a platform without +threads. However, as those are usually the ones with less CPU power I +assume the contention for the CPU would make the game hard to play even +with threads or even without cargodist (autosave ...). I might be wrong, +but I won't put any work into this before someone shows me some problem. + +You can configure the link graph recalculation time. A link graph +recalculation time of X days means that each link graph job has X days +to run before it is joined. The downside is that the flow stats won't be +updated before the job is finished and thus a high value means less +updates and longer times until changes in capacities are accounted for. +If you play a very large map with a complicated link graph you may want to +raise the time setting to avoid lags. The same holds for systems with slow +CPUs. + +Another option to avoid excessive lags is to reduce the accuracy of link +graph calculations. Generally the accuracy is inversely correlated to the +CPU requirements of the MCF algorithm. diff --git a/docs/multiplayer.txt b/docs/multiplayer.txt new file mode 100644 index 0000000..7f4227c --- /dev/null +++ b/docs/multiplayer.txt @@ -0,0 +1,219 @@ +Multiplayer manual for OpenTTD +Last updated: 2011-02-16 +------------------------------------------------------------------------ + + +Table of contents +----------------- +1.0) Starting a server +2.0) Connecting to a server + * 2.1) Connecting to a server over the console +3.0) Playing internet games +4.0) Tips for servers + * 4.1) Imposing landscaping limits +5.0) Some useful things +6.0) Troubleshooting + + +1.0) Starting a server +---- ----------------- + - Make sure that you have your firewall of the computer as well as possible + routers or modems of the server configured such that: + * port 3979 is free for both UDP and TCP connections in- and outgoing + * port 3978 is free outbound for UDP in order to advertise with the master + server (if desired). Otherwise you'll have to tell players your IP. + * port 3977 if use of the admin interface is desired (see admin_network.txt) + - Click "multiplayer" on the startup screen + - Click "start server" + - Type in a game name + - Select the type of game ('LAN/Internet' or 'Internet (advertise)'. With the + last one other people are able to see you online. Else they need your IP and + port to join) + - Click "start game", "load game" or "load scenario" + - Start playing + + +2.0) Connecting to a server +---- ---------------------- + - Click "multiplayer" on the startup screen + + - If you want to connect to any network game in your LAN click on 'LAN', then + on 'Find Server' + - If you want to see which servers all online on the Internet, click on + 'Internet' and 'Find Server' + + - If there were more than one server + - select one in the list below the buttons + - click on 'join game' + + - If you want to play and you have the ip or hostname of the game server you + want connect to. + - click add server + - type in the ip address or hostname + - if you want to add a port use : + + - Now you can select a company and press: "Join company", to help that company + - Or you can press "Spectate game", to spectate the game + - Or you can press "New company", and start your own company (if there are + slots free) + + - You see a progressbar how far you are with joining the server. + + - Happy playing + +2.1) Connecting to a server over the console +---- --------------------------------------- + - Open the console and type in the following command: + connect :# + + +3.0) Playing internet games +---- ---------------------- + - Servers with a red dot behind it have a different version then you have. You + will not be able to join those servers. + + - Servers with a yellow dot behind it have NewGRFs that you do not have. You + will not be able to join those servers. However, via "NewGRF Settings" and + "Find missing content online" you might be able to download the needed + NewGRFs after which you can join the server. + + - It can happen that a connection is that slow, or you have that many clients + connected to your server, that your clients start to loose their connection. + Some things you can do about it: + - [network] frame_freq: + change it in console with: 'set network.frame_freq ' + the number should be between the 0 and 10, not much higher. It indicates + the delay between clicking and showing up. The higher, the more you notice + it, but the less bandwidth you use. + A good value for Internet-games is 2 or 3. + + - [network] sync_freq: + change it in console with: 'set network.sync_freq ' + the number should be between the 50 and 1000, not much lower, not much + higer. It indicates the time between sync-frames. A sync-frame is a frame + which checks if all clients are still in sync. When the value it too high, + clients can desync in 1960, but the server detects it in 1970. Not really + handy. The lower the value, the more bandwidth it uses. + + NB: changing frame_freq has more effect on the bandwidth then sync_freq. + + +4.0) Tips for servers +---- ---------------- + - You can launch a dedicated server by adding -D as parameter. + - In UNIX like systems, you can fork your dedicated server by adding -f as + parameter. + + - You can automaticly clean companies that do not have a client connected to + them, for, let's say, 3 years. You can do this via: 'set autoclean_companies' + and 'set autoclean_protected' and 'set autoclean_unprotected'. Unprotected + removes a password from a company when it is not used for more then the + defined amount of months. 'set autoclean_novehicles' can be used to remove + companies without any vehicles quickly. + + - You can also do this manually via the console: 'reset_company'. + + - You can let your server automaticly restart a map when, let's say, year 2030 + is reached. See 'set restart_game_date' for detail. + + - If you want to be on the server-list, enable Advertising. To do this, select + 'Internet (advertise)' in the Start Server menu, or type in console: + 'set server_advertise 1'. + + - You can protect your server with a password via the console: 'set server_pw', + or via the Start Server menu. + + - When you have many clients connected to your server via Internet, watch your + bandwidth (if you have any limit on it, set by your ISP). One client uses + about 1.5 kilobytes per second up and down. To decrease this amount, setting + 'frame_freq' to 1 will reduce it to roughly 1 kilobyte per second per client. + + - OpenTTD's default settings for maximum number of clients, and amount of data + from clients to process are chosen to not influence the normal playing of + people, but to prevent or at least make it less likely that someone can + perform a (distributed) denial-of-service attack on your server by causing + an out-of-memory event by flooding the server with data to send to all + clients. The major factor in this is the maximum number of clients; with + 32 clients "only" sending one chat message causes 1024 messages to be + distributed in total, with 64 clients that already quadruples to 4096. Given + that upstream bandwidth is usually the limiting factor, a queue of packets + that need to be sent will be created. + To prevent clients from exploiting this "explosion" of packets to send we + limit the number of incoming data, resulting in effectively limiting the + amount of data that OpenTTD will send to the clients. Even with the default + limits it is possible to generate about 70.000 packets per second, or about + 7 megabit per second of traffic. + Given that OpenTTD kicks clients after they have not reacted within about 9 + seconds from sending a frame update packet it would be possible that OpenTTD + keeps about 600.000 packets in memory, using about 50 megabytes of memory. + Given that OpenTTD allows short bursts of packets, you can have slightly + more packets in memory in case of a distributed denial of service attack. + When increasing the amount of incoming data, or the maximum number of + clients the amount of memory OpenTTD needs in case of a distributed denial + of service attack is linearly related to the amount of incoming data and + quadratic to the amount of clients. In short, a rule of thumb for, the + maximum memory usage for packets is: + #max_clients * #max_clients * bytes_per_frame * 10 KiB. + +4.1) Imposing landscaping limits +---- --------------------------- + - You can impose limits on companies by the following 4 settings: + - terraform_per_64k_frames + - terraform_frame_burst + - clear_per_64k_frames + - clear_frame_burst + + - Explaining 'per_64K_frames' and 'burst' + - 'burst' defines 3 things, the maximum limit, the limit of a single action, + and the initial value for the limit assigned to a new company. + This setting is fairly simple and requires no math. + + A value of 1 means a single tile can be affected by a single action. + This results in having to click 400 times when wanting to cover an area + of 20 x 20 tiles. + + The default value 4096 covers an area of 64 x 64 tiles. + + - 'per_64k_frames' defines the number of tiles added to each companies limit + per frame (however not past the possible maximum value,the 'burst'). + 64k rather resembles the exact number of 65536 frames. So setting this + variable to 65536 means: 65536 / 65536 = 1 tile per frame. + As a day consists of 74 frames, a company's limit is increased by 74 + tiles during the course of a single day (2.22 seconds). + + To achieve a 1 tile per day increase the following calculation is needed: + 1 / 74 (frames per day) * 65536 (per_64k_frames) = 885.62... + after rounding: a value of 886 means adding a bit over 1 tile per day. + + There is still enough space to scale this value downwards: + decreasing this value to 127 results in a bit over 1 tile added to the + allowance per week (7 days). + + To create a setup in which a company gets an initial allowance only, + set the value to 0 - no increase of the allowance per frame. + + - Even though construction actions include a clear tile action, they are not + affected by the above settings. + + +5.0) Some useful things +---- ------------------ + - You can protect your company so nobody else can join uninvited. To do this, + set a password in your Company Screen + + - You can give other players some money via the ClientList (under the 'head' + in the mainbar). + + - You can chat with other players via ENTER or via SHIFT+T or via the ClientList + + - Servers can now kick players, so don't make them use it! + + +6.0) Troubleshooting +---- --------------- + - My advertising server does not show up in list at servers.openttd.org + Run openttd with the '-d net=2' parameter. That will show which incoming + communication is received, whether the replies from the master server or + communication from an admin tool reach the programme. See section 1 + 'Starting a server' further up for the ports and protocols used by OpenTTD. + The ports can be configured in the config file. diff --git a/docs/obg_format.txt b/docs/obg_format.txt new file mode 100644 index 0000000..f43ea7e --- /dev/null +++ b/docs/obg_format.txt @@ -0,0 +1,85 @@ +; +; Example file for the OpenTTD Base Graphics replacement sets. +; This file consists of basically two different parts: +; * metadata +; * information about the files +; +; Metadata contains information about the name, version and palette +; of the graphics set. +; +; == Getting started == +; - you can't add comments after values +; - you have to fill the MD5 checksum for each file +; - you may not miss any of the metadata or files items +; - `openttd -h` lists all graphics replacements sets it found to be correct +; - `openttd -d grf=1` shows warnings/errors when parsing an .obg file +; - `openttd -I ` starts OpenTTD with the given set (case sensitive) +; - adding `graphicsset = ` to the misc section of openttd.cfg makes +; OpenTTD start with that graphics set by default +; - there is a command line tool for all platforms called md5sum that can +; create the MD5 checksum you need. +; - all files specified in this file are search relatively to the path where +; this file is found, i.e. if the graphics files are in a subdir you have +; to add that subdir to the names in this file to! It will NOT search for +; a file named like specified in here. + +[metadata] +; the name of the pack, preferably less than 16 characters +name = example +; the short name (4 characters), used to identify this set +shortname = XMPL +; the version of this graphics set (read as single integer) +version = 0 +; a fairly short description of the set +; By adding '.' you can translate the description. +; Note that OpenTTD first tries the full ISO code, then the first +; two characters and then uses the fallback (no '.'). +; The ISO code matching is case sensitive! +; So en_US will be used for en_GB if no en_GB translation is added. +; As a result the below example has 'howdie' for en_US and en_GB but +; 'foo' for all other languages. +description = foo +description.en_US = howdie +; palette used by the set; either DOS or Windows +palette = DOS +; preferred blitter, optional; either 8bpp (default) or 32bpp. +blitter = 8bpp + +; The files section lists the files that replace sprites. +; The file names are case sensitive. +[files] +; GRF file with the base sprites +base = TRG1.GRF +; GRF file with logos, original terrain generator sprites +logos = TRGI.GRF +; GRF file with extra arctic sprites +arctic = TRGC.GRF +; GRF file with extra tropical sprites +tropical = TRGH.GRF +; GRF file with extra toyland sprites +toyland = TRGT.GRF +; NewGRF file using Actions 5, 7, 9 and A to replace sprites +; Must use a GRF ID starting with FF so it cannot be selected from +; the in-game NewGRF list and (thus) be loaded twice. +extra = OPENTTDD.GRF + +; The md5s section lists the MD5 checksum for the files that replace them. +; Note that the list of files is case sensitive. Each GRF listed in the +; files section must be listed here with it's MD5 checksum, otherwise you +; will get a lot of warnings when starting OpenTTD. +[md5s] +TRG1.GRF = 9311676280e5b14077a8ee41c1b42192 +TRGI.GRF = da6a6c9dcc451eec88d79211437b76a8 +TRGH.GRF = ee6616fb0e6ef6b24892c58c93d86fc9 +TRGC.GRF = ed446637e034104c5559b32c18afe78d +TRGT.GRF = fcde1d7e8a74197d72a62695884b909e +OPENTTDD.GRF = f829f62c137d6d7c6e272c481b796dd5 + +; The origin section provides the possibility to put and extra line into +; the warning that a file is missing/corrupt. This can be used to tell +; them where to find it. It works on the filename specified in the +; files section and if that is not found it will fall back to the default +; as shown below here. +[origin] +default = You can find it on your Transport Tycoon Deluxe CD-ROM. +OPENTTDD.GRF = This file was part of your installation. diff --git a/docs/obm_format.txt b/docs/obm_format.txt new file mode 100644 index 0000000..40f829a --- /dev/null +++ b/docs/obm_format.txt @@ -0,0 +1,106 @@ +; +; Example file for the OpenTTD Base Music replacement sets. +; This file consists of basically two different parts: +; * metadata +; * information about the files/songs +; +; Metadata contains information about the name and version +; of the music set. +; +; == Getting started == +; - you can't add comments after values +; - you have to fill the MD5 checksum for each file +; - you may not miss any of the metadata or files items +; - `openttd -h` lists all music replacement sets it found to be correct +; - `openttd -d grf=1` shows warnings/errors when parsing an .obm file +; - `openttd -M ` starts OpenTTD with the given set (case sensitive) +; - adding `musicset = ` to the misc section of openttd.cfg makes +; OpenTTD start with that sound set by default +; - there is a command line tool for all platforms called md5sum that can +; create the MD5 checksum you need. +; - all files specified in this file are search relatively to the path where +; this file is found, i.e. if the sound files are in a subdir you have +; to add that subdir to the names in this file to! It will NOT search for +; a file named like specified in here. + +[metadata] +; the name of the pack, preferably less than 16 characters +name = example +; the short name (4 characters), used to identify this set +shortname = XMPL +; the version of this sound set (read as single integer) +version = 0 +; a fairly short description of the set +; By adding '.' you can translate the description. +; Note that OpenTTD first tries the full ISO code, then the first +; two characters and then uses the fallback (no '.'). +; The ISO code matching is case sensitive! +; So en_US will be used for en_GB if no en_GB translation is added. +; As a result the below example has 'howdie' for en_US and en_GB but +; 'foo' for all other languages. +description = foo +description.en_US = howdie + +; The files section lists the files that replace songs. +; The file names are case sensitive. +; You can have empty file names; in that case no song will be loaded +; for that 'entry'. +[files] +; The theme song for OpenTTD +theme = THEME_SONG.GM +; The songs in the 'old style' category +old_0 = +old_1 = +old_2 = +old_3 = +old_4 = +old_5 = +old_6 = +old_7 = +old_8 = +old_9 = +; The songs in the 'new style' category +new_0 = +new_1 = +new_2 = +new_3 = +new_4 = +new_5 = +new_6 = +new_7 = +new_8 = +new_9 = +; The songs in the 'ezy street' category +ezy_0 = +ezy_1 = +ezy_2 = +ezy_3 = +ezy_4 = +ezy_5 = +ezy_6 = +ezy_7 = +ezy_8 = +ezy_9 = + +; The names section lists the song names for the given file name. +; Note that the list of files is case sensitive. Each file listed in the +; files section must be listed here with it's song name, otherwise you +; will get a lot of warnings when starting OpenTTD. +[names] +THEME_SONG.GM = Tycoon DELUXE Theme + +; The md5s section lists the MD5 checksum for the files that replace them. +; Note that the list of files is case sensitive. Each file listed in the +; files section must be listed here with it's MD5 checksum, otherwise you +; will get a lot of warnings when starting OpenTTD. +[md5s] +THEME_SONG.GM = 45cfec1b9d8c7a0ad45e755833cbf221 + +; The origin section provides the possibility to put and extra line into +; the warning that a file is missing/corrupt. This can be used to tell +; them where to find it. It works on the filename specified in the +; files section and if that is not found it will fall back to the default +; as shown below here. +[origin] +default = You can find it on your Transport Tycoon Deluxe CD-ROM. +THEME_SONG.GM = You can find it also on your Transport Tycoon Deluxe CD-ROM. diff --git a/docs/obs_format.txt b/docs/obs_format.txt new file mode 100644 index 0000000..21bb285 --- /dev/null +++ b/docs/obs_format.txt @@ -0,0 +1,64 @@ +; +; Example file for the OpenTTD Base Sound replacement sets. +; This file consists of basically two different parts: +; * metadata +; * information about the files +; +; Metadata contains information about the name and version +; of the sound set. +; +; == Getting started == +; - you can't add comments after values +; - you have to fill the MD5 checksum for each file +; - you may not miss any of the metadata or files items +; - `openttd -h` lists all sound replacements sets it found to be correct +; - `openttd -d grf=1` shows warnings/errors when parsing an .obs file +; - `openttd -S ` starts OpenTTD with the given set (case sensitive) +; - adding `soundsset = ` to the misc section of openttd.cfg makes +; OpenTTD start with that sound set by default +; - there is a command line tool for all platforms called md5sum that can +; create the MD5 checksum you need. +; - all files specified in this file are search relatively to the path where +; this file is found, i.e. if the sound files are in a subdir you have +; to add that subdir to the names in this file to! It will NOT search for +; a file named like specified in here. + +[metadata] +; the name of the pack, preferably less than 16 characters +name = example +; the short name (4 characters), used to identify this set +shortname = XMPL +; the version of this sound set (read as single integer) +version = 0 +; a fairly short description of the set +; By adding '.' you can translate the description. +; Note that OpenTTD first tries the full ISO code, then the first +; two characters and then uses the fallback (no '.'). +; The ISO code matching is case sensitive! +; So en_US will be used for en_GB if no en_GB translation is added. +; As a result the below example has 'howdie' for en_US and en_GB but +; 'foo' for all other languages. +description = foo +description.en_US = howdie + +; The files section lists the files that replace sprites. +; The file names are case sensitive. +[files] +; The file with the samples. Must contain exactly 73 samples. +samples = SAMPLES.CAT + +; The md5s section lists the MD5 checksum for the files that replace them. +; Note that the list of files is case sensitive. Each file listed in the +; files section must be listed here with it's MD5 checksum, otherwise you +; will get a lot of warnings when starting OpenTTD. +[md5s] +SAMPLES.CAT = 422ea3dd074d2859bb51639a6e0e85da + +; The origin section provides the possibility to put and extra line into +; the warning that a file is missing/corrupt. This can be used to tell +; them where to find it. It works on the filename specified in the +; files section and if that is not found it will fall back to the default +; as shown below here. +[origin] +default = You can find it on your Transport Tycoon Deluxe CD-ROM. +SAMPLES.CAT = You can find it also on your Transport Tycoon Deluxe CD-ROM. diff --git a/docs/openttd.6 b/docs/openttd.6 new file mode 100644 index 0000000..4e04be3 --- /dev/null +++ b/docs/openttd.6 @@ -0,0 +1,153 @@ +.\" Hey, EMACS: -*- nroff -*- +.\" Please adjust this date whenever revising the manpage. +.Dd October 13, 2014 +.Dt OPENTTD 6 +.Os +.Sh NAME +.Nm openttd +.Nd open source clone of the Microprose game \(lqTransport Tycoon Deluxe\(rq +.Sh SYNOPSIS +.Nm +.Op Fl efhx +.Op Fl b Ar blitter +.Op Fl c Ar config_file +.Op Fl d Op Ar level | Ar cat Ns = Ns Ar lvl Ns Op , Ns Ar ... +.Op Fl D Oo Ar host Oc Ns Op : Ns Ar port +.Op Fl g Op Ar savegame +.Op Fl G Ar seed +.Op Fl I Ar graphicsset +.Op Fl l Ar host Ns Op : Ns Ar port +.Op Fl m Ar driver +.Op Fl M Ar musicset +.Op Fl n Ar host Ns Oo : Ns Ar port Oc Ns Op # Ns Ar player +.Op Fl p Ar password +.Op Fl P Ar password +.Op Fl q Ar savegame +.Op Fl r Ar width Ns x Ns Ar height +.Op Fl s Ar driver +.Op Fl S Ar soundset +.Op Fl t Ar year +.Op Fl v Ar driver +.Sh OPTIONS +.Bl -tag -width "-n host[:port][#player]" +.It Fl b Ar blitter +Select the blitter +.Ar blitter ; +see +.Fl h +for a full list. +.It Fl c Ar config_file +Use +.Ar config_file +instead of +.Pa openttd.cfg . +.It Fl d Ar [level] +Set debug verbosity for all categories to +.Ar level , +or 1 if omitted. +.It Fl d Ar cat Ns = Ns Ar lvl Ns Op , Ns Ar ... +Set debug verbosity to +.Ar lvl +for a specific category +.Ar cat . +.It Fl D Oo Ar host Oc Ns Op : Ns Ar port +Start a dedicated server. +.Pp +Network debug level will be set to 6. +If you want to change this, set +.Fl d +after setting +.Fl D . +.It Fl e +Start in world editor mode. +.It Fl f +Fork into background (dedicated server only, see +.Fl D ) . +.It Fl g Op Ar savegame +Load +.Ar savegame +at start or start a new game if omitted. +.Ar savegame +must be either an absolute path or one relative to the current path or one of +the search paths. +.It Fl G Ar seed +Seed the pseudo random number generator with +.Ar seed . +.It Fl h +Display a summary of all options and list all the available AIs, blitters, +sound, music and video drivers, graphics sets and sound sets. +.It Fl I Ar graphicsset +Select the graphics set +.Ar graphicsset ; +see +.Fl h +for a full list. +.It Fl l Ar host Ns Op : Ns Ar port +Redirect +.Fn DEBUG +output; see +.Fl D . +.It Fl m Ar driver +Select the music driver +.Ar driver ; +see +.Fl h +for a full list. +.It Fl M Ar musicset +Select the music set +.Ar musicset ; +see +.Fl h +for a full list. +.It Fl n Ar host Ns Oo : Ns Ar port Oc Ns Op # Ns Ar player +Join a network game, optionally specifying a port to connect to and player to +play as. +.It Fl p Ar password +Password used to join server. +Only useful with +.Fl n . +.It Fl P Ar password +Password used to join company. +Only useful with +.Fl n . +.It Fl q Ar savegame +Write some information about the specified savegame and exit. +.It Fl r Ar width Ns x Ns Ar height +Set the resolution to +.Ar width +\(mu +.Ar height +pixels. +.It Fl s Ar driver +Select the sound driver +.Ar driver ; +see +.Fl h +for a full list. +.It Fl S Ar soundset +Select the sound set +.Ar soundset ; +see +.Fl h +for a full list. +.It Fl t Ar year +Set the starting year to +.Ar year . +.It Fl v Ar driver +Select the video driver +.Ar driver ; +see +.Fl h +for a full list. +.It Fl x +Do not automatically save to config file on exit. +.El +.Sh SEE ALSO +.Lk https://wiki.openttd.org "Wiki" +(includes community maintained manual), +.Lk https://forum.openttd.org "Forum", +.Lk https://www.openttd.org "News" +.Sh HISTORY +Transport Tycoon Deluxe was written by Chris Sawyer and published by Microprose. +.Nm +is a free reimplementation. diff --git a/docs/ottd-colourtext-palette.png b/docs/ottd-colourtext-palette.png new file mode 100644 index 0000000..26cb20f Binary files /dev/null and b/docs/ottd-colourtext-palette.png differ diff --git a/docs/palettes/openttd.gpl b/docs/palettes/openttd.gpl new file mode 100644 index 0000000..357c0bc --- /dev/null +++ b/docs/palettes/openttd.gpl @@ -0,0 +1,260 @@ +GIMP Palette +Name: openttd +Columns: 16 +# + 0 0 255 unnamed +238 0 238 unnamed +239 0 239 unnamed +240 0 240 unnamed +241 0 241 unnamed +242 0 242 unnamed +243 0 243 unnamed +244 0 244 unnamed +245 0 245 unnamed +246 0 246 unnamed +168 168 168 unnamed +184 184 184 unnamed +200 200 200 unnamed +216 216 216 unnamed +232 232 232 unnamed +252 252 252 unnamed + 52 60 72 unnamed + 68 76 92 unnamed + 88 96 112 unnamed +108 116 132 unnamed +132 140 152 unnamed +156 160 172 unnamed +176 184 196 unnamed +204 208 220 unnamed + 48 44 4 unnamed + 64 60 12 unnamed + 80 76 20 unnamed + 96 92 28 unnamed +120 120 64 unnamed +148 148 100 unnamed +176 176 132 unnamed +204 204 168 unnamed +100 100 100 unnamed +116 116 116 unnamed +104 80 44 unnamed +124 104 72 unnamed +152 132 92 unnamed +184 160 120 unnamed +212 188 148 unnamed +244 220 176 unnamed +132 132 132 unnamed + 88 4 16 unnamed +112 16 32 unnamed +136 32 52 unnamed +160 56 76 unnamed +188 84 108 unnamed +204 104 124 unnamed +220 132 144 unnamed +236 156 164 unnamed +252 188 192 unnamed +252 208 0 unnamed +252 232 60 unnamed +252 252 128 unnamed + 76 40 0 unnamed + 96 60 8 unnamed +116 88 28 unnamed +136 116 56 unnamed +156 136 80 unnamed +176 156 108 unnamed +196 180 136 unnamed + 68 24 0 unnamed + 96 44 4 unnamed +128 68 8 unnamed +156 96 16 unnamed +184 120 24 unnamed +212 156 32 unnamed +232 184 16 unnamed +252 212 0 unnamed +252 248 128 unnamed +252 252 192 unnamed + 32 4 0 unnamed + 64 20 8 unnamed + 84 28 16 unnamed +108 44 28 unnamed +128 56 40 unnamed +148 72 56 unnamed +168 92 76 unnamed +184 108 88 unnamed +196 128 108 unnamed +212 148 128 unnamed + 8 52 0 unnamed + 16 64 0 unnamed + 32 80 4 unnamed + 48 96 4 unnamed + 64 112 12 unnamed + 84 132 20 unnamed +104 148 28 unnamed +128 168 44 unnamed + 64 64 64 unnamed + 44 68 32 unnamed + 60 88 48 unnamed + 80 104 60 unnamed +104 124 76 unnamed +128 148 92 unnamed +152 176 108 unnamed +180 204 124 unnamed + 16 52 24 unnamed + 32 72 44 unnamed + 56 96 72 unnamed + 76 116 88 unnamed + 96 136 108 unnamed +120 164 136 unnamed +152 192 168 unnamed +184 220 200 unnamed + 32 24 0 unnamed + 56 28 0 unnamed + 80 80 80 unnamed + 88 52 12 unnamed +104 64 24 unnamed +124 84 44 unnamed +140 108 64 unnamed +160 128 88 unnamed + 76 40 16 unnamed + 96 52 24 unnamed +116 68 40 unnamed +136 84 56 unnamed +164 96 64 unnamed +184 112 80 unnamed +204 128 96 unnamed +212 148 112 unnamed +224 168 128 unnamed +236 188 148 unnamed + 80 28 4 unnamed +100 40 20 unnamed +120 56 40 unnamed +140 76 64 unnamed +160 100 96 unnamed +184 136 136 unnamed + 36 40 68 unnamed + 48 52 84 unnamed + 64 64 100 unnamed + 80 80 116 unnamed +100 100 136 unnamed +132 132 164 unnamed +172 172 192 unnamed +212 212 224 unnamed + 48 48 48 unnamed + 64 44 144 unnamed + 88 64 172 unnamed +104 76 196 unnamed +120 88 224 unnamed +140 104 252 unnamed +160 136 252 unnamed +188 168 252 unnamed + 0 24 108 unnamed + 0 36 132 unnamed + 0 52 160 unnamed + 0 72 184 unnamed + 0 96 212 unnamed + 24 120 220 unnamed + 56 144 232 unnamed + 88 168 240 unnamed +128 196 252 unnamed +188 224 252 unnamed + 16 64 96 unnamed + 24 80 108 unnamed + 40 96 120 unnamed + 52 112 132 unnamed + 80 140 160 unnamed +116 172 192 unnamed +156 204 220 unnamed +204 240 252 unnamed +172 52 52 unnamed +212 52 52 unnamed +252 52 52 unnamed +252 100 88 unnamed +252 144 124 unnamed +252 184 160 unnamed +252 216 200 unnamed +252 244 236 unnamed + 72 20 112 unnamed + 92 44 140 unnamed +112 68 168 unnamed +140 100 196 unnamed +168 136 224 unnamed +200 176 248 unnamed +208 184 255 unnamed +232 208 252 unnamed + 60 0 0 unnamed + 92 0 0 unnamed +128 0 0 unnamed +160 0 0 unnamed +196 0 0 unnamed +224 0 0 unnamed +252 0 0 unnamed +252 80 0 unnamed +252 108 0 unnamed +252 136 0 unnamed +252 164 0 unnamed +252 192 0 unnamed +252 220 0 unnamed +252 252 0 unnamed +204 136 8 unnamed +228 144 4 unnamed +252 156 0 unnamed +252 176 48 unnamed +252 196 100 unnamed +252 216 152 unnamed + 8 24 88 unnamed + 12 36 104 unnamed + 20 52 124 unnamed + 28 68 140 unnamed + 40 92 164 unnamed + 56 120 188 unnamed + 72 152 216 unnamed +100 172 224 unnamed + 92 156 52 unnamed +108 176 64 unnamed +124 200 76 unnamed +144 224 92 unnamed +224 244 252 unnamed +200 236 248 unnamed +180 220 236 unnamed +132 188 216 unnamed + 88 152 172 unnamed + 16 16 16 unnamed + 32 32 32 unnamed + 32 68 112 unnamed + 36 72 116 unnamed + 40 76 120 unnamed + 44 80 124 unnamed + 48 84 128 unnamed + 72 100 144 unnamed +100 132 168 unnamed +216 244 252 unnamed + 96 128 164 unnamed + 68 96 140 unnamed + 76 24 8 unnamed +108 44 24 unnamed +144 72 52 unnamed +176 108 84 unnamed +210 146 126 unnamed +252 60 0 unnamed +252 84 0 unnamed +252 104 0 unnamed +252 124 0 unnamed +252 148 0 unnamed +252 172 0 unnamed +252 196 0 unnamed + 64 0 0 unnamed +255 0 0 unnamed + 48 48 0 unnamed + 64 64 0 unnamed + 80 80 0 unnamed +255 255 0 unnamed +148 148 148 unnamed +247 0 247 unnamed +248 0 248 unnamed +249 0 249 unnamed +250 0 250 unnamed +251 0 251 unnamed +252 0 252 unnamed +253 0 253 unnamed +254 0 254 unnamed +255 0 255 unnamed +255 255 255 unnamed diff --git a/docs/palettes/palette.act b/docs/palettes/palette.act new file mode 100644 index 0000000..87f586e Binary files /dev/null and b/docs/palettes/palette.act differ diff --git a/docs/tileh.png b/docs/tileh.png new file mode 100644 index 0000000..22e2c0b Binary files /dev/null and b/docs/tileh.png differ diff --git a/findversion.sh b/findversion.sh new file mode 100755 index 0000000..6be52b6 --- /dev/null +++ b/findversion.sh @@ -0,0 +1,147 @@ +#!/bin/sh + +# $Id$ + +# This file is part of OpenTTD. +# OpenTTD 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, version 2. +# OpenTTD 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 OpenTTD. If not, see . + + +# Arguments given? Show help text. +if [ "$#" != "0" ]; then + cat <\t\t\t +REV + a string describing what version of the code the current checkout is + based on. The exact format of this string depends on the version + control system in use, but it tries to identify the revision used as + close as possible (using the svn revision number or hg/git hash). + This also includes an indication of whether the checkout was + modified and which branch was checked out. This value is not + guaranteed to be sortable, but is mainly meant for identifying the + revision and user display. + + If no revision identifier could be found, this is left empty. +REV_NR + the revision number of the svn revision this checkout is based on. + This can be used to determine which functionality is present in this + checkout. For trunk svn checkouts and hg/git branches based upon it, + this number should be accurate. For svn branch checkouts, this + number is mostly meaningless, at least when comparing with the + REV_NR from other branches or trunk. + + This number should be sortable. Within a given branch or trunk, a + higher number means a newer version. However, when using git or hg, + this number will not increase on new commits. + + If no revision number could be found, this is left empty. +MODIFIED + Whether (the src directory of) this checkout is modified or not. A + value of 0 means not modified, a value of 2 means it was modified. + Modification is determined in relation to the commit identified by + REV, so not in relation to the svn revision identified by REV_NR. + + A value of 1 means that the modified status is unknown, because this + is not an svn/git/hg checkout for example. + +CLEAN_REV + the same as REV but without branch name + +By setting the AWK environment variable, a caller can determine which +version of "awk" is used. If nothing is set, this script defaults to +"awk". +EOF +exit 1; +fi + +# Allow awk to be provided by the caller. +if [ -z "$AWK" ]; then + AWK=awk +fi + +# Find out some dirs +cd `dirname "$0"` +ROOT_DIR=`pwd` + +# Determine if we are using a modified version +# Assume the dir is not modified +MODIFIED="0" +if [ -d "$ROOT_DIR/.svn" ] || [ -d "$ROOT_DIR/../.svn" ]; then + # We are an svn checkout + if [ -n "`svnversion | grep 'M'`" ]; then + MODIFIED="2" + fi + # Find the revision like: rXXXXM-branch + BRANCH=`LC_ALL=C svn info | "$AWK" '/^URL:.*branches/ { split($2, a, "/"); for(i in a) if (a[i]=="branches") { print a[i+1]; break } }'` + TAG=`LC_ALL=C svn info | "$AWK" '/^URL:.*tags/ { split($2, a, "/"); for(i in a) if (a[i]=="tags") { print a[i+1]; break } }'` + REV_NR=`LC_ALL=C svn info | "$AWK" '/^Last Changed Rev:/ { print $4 }'` + if [ -n "$TAG" ]; then + REV=$TAG + else + REV="r$REV_NR" + fi +elif [ -d "$ROOT_DIR/.git" ]; then + # We are a git checkout + # Refresh the index to make sure file stat info is in sync, then look for modifications + git update-index --refresh >/dev/null + if [ -n "`git diff-index HEAD`" ]; then + MODIFIED="2" + fi + HASH=`LC_ALL=C git rev-parse --verify HEAD 2>/dev/null` + REV="g`echo $HASH | cut -c1-8`" + BRANCH="`git symbolic-ref -q HEAD 2>/dev/null | sed 's@.*/@@;s@^master$@@'`" + REV_NR=`LC_ALL=C git log --pretty=format:%s --grep="^(svn r[0-9]*)" -1 | sed "s@.*(svn r\([0-9]*\)).*@\1@"` + if [ -z "$REV_NR" ]; then + # No rev? Maybe it is a custom git-svn clone + REV_NR=`LC_ALL=C git log --pretty=format:%b --grep="git-svn-id:.*@[0-9]*" -1 | sed "s@.*\@\([0-9]*\).*@\1@"` + fi + TAG="`git name-rev --name-only --tags --no-undefined HEAD 2>/dev/null | sed 's@\^0$@@'`" + if [ -n "$TAG" ]; then + BRANCH="" + REV="$TAG" + fi +elif [ -d "$ROOT_DIR/.hg" ]; then + # We are a hg checkout + if [ -n "`HGPLAIN= hg status | grep -v '^?'`" ]; then + MODIFIED="2" + fi + HASH=`LC_ALL=C HGPLAIN= hg id -i | cut -c1-12` + REV="h`echo $HASH | cut -c1-8`" + BRANCH="`HGPLAIN= hg branch | sed 's@^default$@@'`" + TAG="`HGPLAIN= hg id -t | grep -v 'tip$'`" + if [ -n "$TAG" ]; then + BRANCH="" + REV="$TAG" + fi + REV_NR=`LC_ALL=C HGPLAIN= hg log -f -k "(svn r" -l 1 --template "{desc|firstline}\n" | grep "^(svn r[0-9]*)" | sed "s@.*(svn r\([0-9]*\)).*@\1@"` + if [ -z "$REV_NR" ]; then + # No rev? Maybe it is a custom hgsubversion clone + REV_NR=`LC_ALL=C HGPLAIN= hg parent --template="{svnrev}"` + fi +elif [ -f "$ROOT_DIR/.ottdrev" ]; then + # We are an exported source bundle + cat $ROOT_DIR/.ottdrev + exit +else + # We don't know + MODIFIED="1" + BRANCH="" + REV="" + REV_NR="" +fi + +if [ "$MODIFIED" -eq "2" ]; then + REV="${REV}M" +fi + +CLEAN_REV=${REV} + +if [ -n "$BRANCH" ]; then + REV="${REV}-$BRANCH" +fi + +echo "$REV $REV_NR $MODIFIED $CLEAN_REV" diff --git a/known-bugs.txt b/known-bugs.txt new file mode 100644 index 0000000..ed10aab --- /dev/null +++ b/known-bugs.txt @@ -0,0 +1,455 @@ +OpenTTD's known bugs +Last updated: 2015-12-01 +Release version: 1.5.3 +------------------------------------------------------------------------ + + +Table of contents +----------------- +1.0) About +2.0) Known bugs + + +1.0) About +---- ----- +All bugs listed below are marked as known. Please do not submit any bugs +that are the same as these. If you do, do not act surprised, because +we WILL flame you!! + +The current list of known bugs that we intend to fix can be found in our +bug tracking system at: http://bugs.openttd.org +Also check the closed bugs when searching for your bug in this system as +we might have fixed the bug in the mean time. + + +2.0) Known bugs +---- ---------------------------------- +This section lists all known bugs that we do not intend to fix and the +reasons why we think that fixing them is infeasible. We might make some +minor improvements that reduce the scope of these bugs, but we will not +be able to completely fix them. + +No suitable AI can be found + If you have no AIs and an AI is started the so-called 'dummy' AI will + be loaded. This AI does nothing but writing a message on the AI debug + window and showing a red warning. There are basically two solutions + for this problem: Either you set the number of AI players to 0 so that + no AI is started. You find that setting at the top of the window in the + "AI / Game Scripts Settings" window. + The other solution is acquiring (downloading) some AI. The easiest way + to do this is via the "Check Online Content" button in the main (intro) + menu or directly in the "AI / Game Scripts Settings" dialogue via the + "Check Online Content" button. + +After a while of playing, colours get corrupted + In Windows 7 the background slideshow corrupts the colour mapping of + OpenTTD's 8bpp screen modes. Workarounds for this are: + a) Switching to windowed mode, instead of fullscreen + b) Switching off background slideshow + c) Setting up the 32bpp-anim or 32bpp-optimized blitter + +Long delay between switching songs/music + On Windows there is a delay of a (few) second(s) between switching of + songs for the "win32" driver. This delay is caused by the fact that + opening a MIDI file via MCI is extremely slow. + + DirectMusic, known as "dmusic" in OpenTTD, has a much shorter delay. + However, under some circumstances DirectMusic does not reset its + state properly causing wrongly pitched/bad sounding songs. This + problem is in DirectMusic as it is reproducable with Microsoft's + DirectMusic Producer. DirectMusic has been deprecated since 2004 + and as such has no support for 64 bits OpenTTD. + + As a delay is favourable over bad sounding music the "win32" driver + is the default driver for OpenTTD. You can change this default by + setting the "musicdriver" in your openttd.cfg to "dmusic". + +Custom vehicle type name is incorrectly aligned + Some NewGRFs use sprites that are bigger than normal in the "buy + vehicle" window. Due to this they have to encode an offset for the + vehicle type name. Upon renaming the vehicle type this encoded offset + is stripped from the name because the "edit box" cannot show this + encoding. As a result the custom vehicle type names will get the + default alignment. The only way to (partly) fix this is by adding + spaces to the custom name. + +Clipping problems [FS#119] + In some cases sprites are not drawn as one would expect. Examples of + this are aircraft that might be hidden below the runway or trees that + in some cases are rendered over vehicles. + The primary cause of this problem is that OpenTTD does not have enough + data (like a 3D model) to properly determine what needs to be drawn in + front of what. OpenTTD has bounding boxes but in lots of cases they + are either too big or too small and then cause problems with what + needs to be drawn in front of what. Also some visual tricks are used. + For example trains at 8 pixels high, the catenary needs to be drawn + above that. When you want to draw bridges on top of that, which are + only one height level (= 8 pixels) higher, you are getting into some + big problems. + We can not change the height levels; it would require us to either + redraw all vehicle or all landscape graphics. Doing so would mean we + leave the Transport Tycoon graphics, which in effect means OpenTTD + will not be a Transport Tycoon clone anymore. + +Mouse scrolling not possible at the edges of the screen [FS#383] [FS#3966] + Scrolling the viewport with the mouse cursor at the edges of the screen + in the same direction of the edge will fail. If the cursor is near the + edge the scrolling will be very slow. + OpenTTD only receives cursor position updates when the cursor is inside + OpenTTD's window. It is not told how far you have moved the cursor + outside of OpenTTD's window. + +Lost trains ignore (block) exit signals [FS#1473] + If trains are lost they ignore block exit signals, blocking junctions + with presignals. This is caused because the path finders cannot tell + where the train needs to go. As such a random direction is chosen at + each junction. This causes the trains to occasionally to make choices + that are unwanted from a player's point of view. + This will not be fixed because lost trains are in almost all cases a + network problem, e.g. a train can never reach a specific place. This + makes the impact of fixing the bug enormously small against the + amount of work needed to write a system that prevents the lost trains + from taking the wrong direction. + +Vehicle owner of last transfer leg gets paid for all [FS#2427] + When you make a transfer system that switches vehicle owners. This + is only possible with 'industry stations', e.g. the oil rig station + the owner of the vehicle that does the final delivery gets paid for + the whole trip. It is not shared amongst the different vehicle + owners that have participated in transporting the cargo. + This sharing is not done because it would enormously increase the + memory and CPU usage in big games for something that is happening + in only one corner case. We think it is not worth the effort until + sharing of stations is an official feature. + +Forbid 90 degree turns does not work for crossing PBS paths [FS#2737] + When you run a train through itself on a X junction with PBS turned on + the train will not obey the 'forbid 90 degree turns' setting. This is + due to the fact that we can not be sure that the setting was turned + off when the track was reserved, which means that we assume it was + turned on and that the setting does not hold at the time. We made it + this way to allow one to change the setting in-game, but it breaks + slightly when you are running your train through itself. Running a + train through means that your network is broken and is thus a user + error which OpenTTD tries to graciously handle. + Fixing this bug means that we need to record whether this particular + setting was turned on or off at the time the reservation was made. This + means adding quite a bit of data to the savegame for solving an issue + that is basically an user error. We think it is not worth the effort. + +Duplicate (station) names after renaming [FS#3204] + After renaming stations one can create duplicate station names. This + is done giving a station the same custom name as another station with + an automatically generated name. + The major part of this problem is that station names are translatable. + Meaning that a station is called e.g. ' Central' in English and + ' Centraal' in Dutch. This means that in network games the + renaming of a town could cause the rename to succeed on some clients + and fail at others. This creates an inconsistent game state that will + be seen as a 'desync'. Secondly the custom names are intended to fall + completely outside of the ' ' naming of stations, so when + you rename a town all station names are updated accordingly. + As a result the decision has been made that all custom names are only + compared to the other custom names in the same class and not compared + to the automatically generated names. + +Extreme CPU usage/hangs when using SDL and PulseAudio [FS#3294] +OpenTTD hangs/freezes when closing, OpenTTD is slow, OpenTTD uses a lot of CPU + OpenTTD can be extremely slow/use a lot of CPU when the sound is + played via SDL and then through PulseAudio's ALSA wrapper. Under the + same configuration OpenTTD, or rather SDL, might hang when exiting + the game. This problem is seen most in Ubuntu 9.04 and higher. + + This is because recent versions of the PulseAudio sound server are + configured to use timer-based audio scheduling rather than + interrupt-based audio scheduling. Configuring PulseAudio to force + use of interrupt-based scheduling may resolve sound problems for + some users. Under recent versions of Ubuntu Linux (9.04 and higher) + this can be accomplished by changing the following line in the + /etc/pulse/default.pa file: + load-module module-udev-detect + to + load-module module-udev-detect tsched=0 + Note that PulseAudio must be restarted for changes to take effect. + Older versions of PulseAudio may use the module-hal-detect module + instead. Adding tsched=0 to the end of that line will have a similar + effect. + + Another possible solution is selecting the "pulse" backend of SDL + by either using "SDL_AUDIODRIVER=pulse openttd" at the command + prompt or installing the 'libsdl1.2debian-pulseaudio' package from + Ubuntu's Universe repository. For other distributions a similar + package needs to be installed. + +OpenTTD not properly resizing with SDL on X [FS#3305] + Under some X window managers OpenTTD's window does not properly + resize. You will either end up with a black bar at the right/bottom + side of the window or you cannot see the right/bottom of the window, + e.g you cannot see the status bar. The problem is that OpenTTD does + not always receive a resize event from SDL making it impossible for + OpenTTD to know that the window was resized; sometimes moving the + window will solve the problem. + Window managers that are known to exhibit this behaviour are KDE's + and GNOME's. With the XFCE's and LXDE's window managers the resize + event is sent when the user releases the mouse. + +Incorrect colours, crashes upon exit, debug warnings and smears upon +window resizing with SDL on Mac OS X [FS#3447] + Video handling with (lib)SDL under Mac OS X is known to fail on some + versions of Mac OS X with some hardware configurations. Some of the + problems happen only under some circumstances whereas others are + always present. + We suggest that the SDL video/sound backend is not used for OpenTTD + in combinations with Mac OS X. + +Train crashes entering same junction from block and path signals [FS#3928] + When a train has reserved a path from a path signal to a two way + block signal and the reservation passes a path signal through the + back another train can enter the reserved path (only) via that same + two way block signal. + The reason for this has to do with optimisation; to fix this issue + the signal update has to pass all path signals until it finds either + a train or a backwards facing signal. This is a very expensive task. + The (signal) setups that allow these crashes can furthermore be + considered incorrectly signalled; one extra safe waiting point for + the train entering from path signal just after the backwards facing + signal (from the path signal train) resolves the issue. + +Crashes when playing music [FS#3941] + Mac OS X's QuickTime (default music driver) and Windows' MCI (win32 + music driver) crash on some songs from OpenMSX. OpenTTD cannot do + anything about this. Please report these crashes to the authors of + OpenMSX so the crash causing songs can be removed or fixed. + +Crashes when run in a VM using Parallels Desktop [FS#4003] + When the Windows version of OpenTTD is executed in a VM under + Parallels Desktop a privileged instruction exception may be thrown. + As OpenTTD works natively on OSX as well as natively on Windows and + these native builds both don't exhibit this behaviour this crash is + most likely due to a bug in the virtual machine, something out of + the scope of OpenTTD. Most likely this is due to Parallels Desktop + lacking support for RDTSC calls. The problem can be avoided by using + other VM-software, Wine, or running natively on OSX. + +OpenTTD hangs when started on 32 bits Windows [FS#4083] + Under some circumstances OpenTTD might hang for hours on the + initialisation of the music driver. The exact circumstances are + unknown except that it is the "dmusic" music driver that has the + problem and that the "win32" music driver does not. + As a result using the "win32" music driver will work around this + issue. + + As the exact circumstances are unknown, and the obvious + configuration settings related to the music driver are at their + default we are not able to detect this failure, except when Windows' + music initialisation function returns after several hours and then + there is no point in switching the music driver anymore. + The reason we still use the "win32" music driver as default are + described in the "Long delay between switching music/song" section + of this document. + +Pre- and exit signals are not dragged [FS#4378] + Unlike all other signal types, the entry- and exit signals are not + dragged but instead normal signals are placed on subsequent track + sections. This is done on purpose as this is the usually more con- + venient solution. There are little to no occasions where more than + one entry or exit signal in a row are useful. This is different + for all other signal types where several in a row can serve one + purpose or another. + +Station build date is incorrect [FS#4415] + The tile query tool will show the date of the last (re)construction + at the station and not the date of the first construction. This is + due to compatability reasons with NewGRFs and the fact that it is + wrong to say that the station is built in a particular year when it + was completely destroyed/rebuilt later on. + The tile query tool can be fixed by changing the "Build date" text + to "Date at which the last (re)construction took place" but this is + deemed too specific and long for that window. + +Can't change volume inside OpenTTD [FS#4416] + Some backends do not provide a means to change the volume of sound + effects or music. The mixing of music and sound is left to external + libraries/the operating system we can't handle the volume control + in OpenTTD. As a result you can't change the volume inside OpenTTD + for backends such as SDL; just use the volume control provided by + your operating system. + +Can't run OpenTTD with the -d option from a MSYS console [FS#4587] + The MSYS console does not allow OpenTTD to open an extra console for + debugging output. Compiling OpenTTD with the --enable-console + configure option prevents this issue and allows the -d option to use + the MSYS console for its output. + +Unreadable characters for non-latin locales [FS#4607] + OpenTTD does not ship a non-latin font in its graphics files. As a + result OpenTTD needs to acquire the font from somewhere else. What + OpenTTD does is ask the operating system, or a system library, for + the best font for a given language if the currently loaded font + does not provide all characters of the chosen translation. This + means that OpenTTD has no influence over the quality of the chosen + font; it just does the best it can do. + + If the text is unreadable there are several steps that you can take + to improve this. The first step is finding a good font and configure + this in the configuration file. See section 9.0 of readme.txt for + more information. You can also increase the font size to make the + characters bigger and possible better readable. + + If the problem is with the clarity of the font you might want to + enable anti-aliasing by setting the small_aa/medium_aa/large_aa + settings to "true". However, anti-aliasing only works when a 32 bits + blitter has been selected, e.g. blitter = "32bpp-anim", as with the + 8 bits blitter there are not enough colours to properly perform the + anti-aliasing. + +(Temporary) wrong colours when switching to full screen [FS#4511]: + On Windows it can happen that you temporarily see wrong colours + when switching to full screen OpenTTD, either by starting + OpenTTD in full screen mode, changing to full screen mode or by + ALT-TAB-ing into a full screen OpenTTD. This is caused by the + fact that OpenTTD, by default, uses 8bpp paletted output. The + wrong colours you are seeing is a temporary effect of the video + driver switching to 8bpp palette mode. + + This issue can be worked around in two ways: + a) Setting fullscreen_bpp to 32 + b) Setting up the 32bpp-anim or 32bpp-optimized blitter + +Train does not crash with itself [FS#4635]: + When a train drives in a circle the front engine passes through + wagons of the same train without crashing. This is intentional. + Signals are only aware of tracks, they do not consider the train + length and whether there would be enough room for a train in some + circle it might drive on. Also the path a train might take is not + necessarily known when passing a signal. + Checking all circumstances would take a lot of additional computational + power for signals, which is not considered worth the effort, as + it does not add anything to gameplay. + Nevertheless trains shall not crash in normal operation, so making + a train not crash with itself is the best solution for everyone. + +Aircraft coming through wall in rotated airports [FS#4705]: + With rotated airports, specifically hangars, you will see that the + aircraft will show a part through the back wall of the hangar. + This can be solved by only drawing a part of the plane when being + at the back of the hangar, however then with transparency turned on + the aircraft would be shown partially which would be even weirder. + As such the current behaviour is deemed the least bad. + The same applies to overly long ships and their depots. + +Vehicles not keeping their "maximum" speed [FS#4815]: + Vehicles that have not enough power to reach and maintain their + advertised maximum speed might be constantly jumping between two + speeds. This is due to the fact that speed and its calculations + are done with integral numbers instead of floating point numbers. + As a result of this a vehicle will never reach its equilibrium + between the drag/friction and propulsion. So in effect it will be + in a vicious circle of speeding up and slowing down due to being + just at the other side of the equilibrium. + + Not speeding up when near the equilibrium will cause the vehicle + to never come in the neighbourhood of the equilibrium and not + slowing down when near the equilibrium will cause the vehicle + to never slow down towards the equilibrium once it has come down + a hill. + + It is possible to calculate whether the equilibrium will be + passed, but then all acceleration calculations need to be done + twice. + +Settings not saved when OpenTTD crashes [FS#4846]: + The settings are not saved when OpenTTD crashes for several reasons. + The most important is that the game state is broken and as such the + settings might contain invalid values, or the settings have not even + been loaded yet. This would cause invalid or totally wrong settings + to be written to the configuration file. + + A solution to that would be saving the settings whenever one changes, + however due to the way the configuration file is saved this requires + a flush of the file to the disk and OpenTTD needs to wait till that + is finished. On some file system implementations this causes the + flush of all 'write-dirty' caches, which can be a significant amount + of data to be written. This can further be aggravated by spinning + down disks to conserve power, in which case this disk needs to be + spun up first. This means that many seconds may pass before the + configuration file is actually written, and all that time OpenTTD + will not be able to show any progress. Changing the way the + configuration file is saved is not an option as that leaves us more + vulnerable to corrupt configuration files. + + Finally, crashes should not be happening. If they happen they should + be reported and fixed, so essentially fixing this is fixing the + wrong thing. If you really need the configuration changes to be + saved, and you need to run a version that crashes regularly, then + you can use the 'saveconfig' command in the console to save the + settings. + +Not all NewGRFs, AIs, game scripts are found [FS#4887]: + Under certain situations, where the path for the content within a + tar file is the same as other content on the file system or in another + tar file, it is possible that content is not found. A more thorough + explanation and solutions are described in section 4.4 of readme.txt. + +Mouse cursor going missing with SDL [FS#4997]: + Under certain circumstances SDL does not notify OpenTTD of changes + with respect to the mouse pointer, specifically whether the mouse + pointer is within the bounds of OpenTTD or not. For example, if you + Alt-tab to another application the mouse cursor will still be shown + in OpenTTD, and when you move the mouse outside of the OpenTTD + window so the cursor gets hidden, open/move another application on + top of the OpenTTD window and then Alt-tab back into OpenTTD the + cursor will not be shown. + + We cannot fix this problem as SDL simply does not provide the + required information in these corner cases. This is a bug in SDL + and as such there is little that we can do about it. + +Inconsistent catchment areas [FS#5661]: + Due to performance decisions the catchment area for cargo accepted + by a station for delivery to houses or industries differs from the + catchment area for cargo that is delivered to stations from houses + or industries. + + Conceptually they work the same, but the effect in game differs. + They work by finding the closest destination "around" the source + which is within a certain distance. This distance depends on the + type of station, e.g. road stops have a smaller catchment area than + large airports. In both cases the bounding box, the smallest + rectangle that contains all tiles of something, is searched for the + target of the cargo, and then spiraling outwards finding the closest + tile of the target. + + In the case of a station with two tiles spread far apart with a house + that is within the station's bounding box, it would be possible that + the spiraling search from the house does not reach one of the station + tiles before the search ends, i.e. all tiles within that distance + are searched. So the house does not deliver cargo to the station. On + the other hand, the station will deliver cargo because the house + falls within the bounding box, and thus search area. + + It is possible to make these consistent, but then cargo from a house + to a station needs to search up to 32 tiles around itself, i.e. 64 + by 64 tiles, to find all possible stations it could deliver to + instead of 10 by 10 tiles (40 times more tiles). Alternatively the + search from a station could be changed to use the actual tiles, but + that would require considering checking 10 by 10 tiles for each of + the tiles of a station, instead of just once. + +Trains might not stop at platforms that are currently being changed [FS#5553]: + If you add tiles to or remove tiles from a platform while a train is + approaching to stop at the same platform, that train can miss the place + where it's supposed to stop and pass the station without stopping. This + is caused by the fact that the train is considered to already have stopped + if it's beyond its assigned stopping location. We can't let the train stop + just anywhere in the station because then it would never leave the station + if you have the same station in the order list multiple times in a row or + if there is only one station in the order list (see FS#5684). + +Some houses and industries are not affected by transparency [FS#5817]: + Some of the default houses and industries (f.e. the iron ore mine) are + not affected by the transparency options. This is because the graphics do + not (completely) separate the ground from the building. + This is a bug of the original graphics, and unfortunately cannot be + fixed with OpenGFX for the sake of maintaining compatibility with the + original graphics. diff --git a/media/baseset/no_music.obm b/media/baseset/no_music.obm new file mode 100644 index 0000000..fd75cfe --- /dev/null +++ b/media/baseset/no_music.obm @@ -0,0 +1,50 @@ +; $Id$ +; +; This represents more or less nothingness +; +[metadata] +name = NoMusic +shortname = NULL +version = 0 +fallback = true +!! description STR_BASEMUSIC_NONE_DESCRIPTION + +[files] +theme = +old_0 = +old_1 = +old_2 = +old_3 = +old_4 = +old_5 = +old_6 = +old_7 = +old_8 = +old_9 = +new_0 = +new_1 = +new_2 = +new_3 = +new_4 = +new_5 = +new_6 = +new_7 = +new_8 = +new_9 = +ezy_0 = +ezy_1 = +ezy_2 = +ezy_3 = +ezy_4 = +ezy_5 = +ezy_6 = +ezy_7 = +ezy_8 = +ezy_9 = + +[md5s] + +[names] + +[origin] +default = This file was part of your OpenTTD installation. diff --git a/media/baseset/no_sound.obs b/media/baseset/no_sound.obs new file mode 100644 index 0000000..e9d5741 --- /dev/null +++ b/media/baseset/no_sound.obs @@ -0,0 +1,18 @@ +; $Id$ +; +; This represents more or less nothingness +; +[metadata] +name = NoSound +shortname = NULL +version = 2 +fallback = true +!! description STR_BASESOUNDS_NONE_DESCRIPTION + +[files] +samples = + +[md5s] + +[origin] +default = This file was part of your OpenTTD installation. diff --git a/media/baseset/orig_dos.obg b/media/baseset/orig_dos.obg new file mode 100644 index 0000000..b4cde64 --- /dev/null +++ b/media/baseset/orig_dos.obg @@ -0,0 +1,31 @@ +; $Id$ +; +; This represents the original graphics as on the non-German Transport +; Tycoon Deluxe DOS CD. +; +[metadata] +name = original_dos +shortname = TTDD +version = 1 +palette = DOS +!! description STR_BASEGRAPHICS_DOS_DESCRIPTION + +[files] +base = TRG1.GRF +logos = TRGI.GRF +arctic = TRGC.GRF +tropical = TRGH.GRF +toyland = TRGT.GRF +extra = OPENTTD.GRF + +[md5s] +TRG1.GRF = 9311676280e5b14077a8ee41c1b42192 +TRGI.GRF = da6a6c9dcc451eec88d79211437b76a8 +TRGC.GRF = ed446637e034104c5559b32c18afe78d +TRGH.GRF = ee6616fb0e6ef6b24892c58c93d86fc9 +TRGT.GRF = e30e8a398ae86c03dc534a8ac7dfb3b6 +OPENTTD.GRF = + +[origin] +default = You can find it on your Transport Tycoon Deluxe CD-ROM. +OPENTTD.GRF = This file was part of your OpenTTD installation. diff --git a/media/baseset/orig_dos.obs b/media/baseset/orig_dos.obs new file mode 100644 index 0000000..e095b62 --- /dev/null +++ b/media/baseset/orig_dos.obs @@ -0,0 +1,19 @@ +; $Id$ +; +; This represents the original sounds as on the Transport +; Tycoon Deluxe DOS CD. +; +[metadata] +name = original_dos +shortname = TTDO +version = 0 +!! description STR_BASESOUNDS_DOS_DESCRIPTION + +[files] +samples = SAMPLE.CAT + +[md5s] +SAMPLE.CAT = 422ea3dd074d2859bb51639a6e0e85da + +[origin] +default = You can find it on your Transport Tycoon Deluxe CD-ROM. diff --git a/media/baseset/orig_dos_de.obg b/media/baseset/orig_dos_de.obg new file mode 100644 index 0000000..8cfcc27 --- /dev/null +++ b/media/baseset/orig_dos_de.obg @@ -0,0 +1,31 @@ +; $Id$ +; +; This represents the original graphics as on the German Transport +; Tycoon Deluxe DOS CD. It contains one broken sprite. +; +[metadata] +name = original_dos_de +shortname = TTDD +version = 0 +palette = DOS +!! description STR_BASEGRAPHICS_DOS_DE_DESCRIPTION + +[files] +base = TRG1.GRF +logos = TRGI.GRF +arctic = TRGC.GRF +tropical = TRGH.GRF +toyland = TRGT.GRF +extra = OPENTTD.GRF + +[md5s] +TRG1.GRF = 9311676280e5b14077a8ee41c1b42192 +TRGI.GRF = da6a6c9dcc451eec88d79211437b76a8 +TRGC.GRF = ed446637e034104c5559b32c18afe78d +TRGH.GRF = ee6616fb0e6ef6b24892c58c93d86fc9 +TRGT.GRF = fcde1d7e8a74197d72a62695884b909e +OPENTTD.GRF = + +[origin] +default = You can find it on your Transport Tycoon Deluxe CD-ROM. +OPENTTD.GRF = This file was part of your OpenTTD installation. diff --git a/media/baseset/orig_win.obg b/media/baseset/orig_win.obg new file mode 100644 index 0000000..82a5c2a --- /dev/null +++ b/media/baseset/orig_win.obg @@ -0,0 +1,31 @@ +; $Id$ +; +; This represents the original graphics as on the Transport +; Tycoon Deluxe for Windows CD. +; +[metadata] +name = original_windows +shortname = TTDW +version = 0 +palette = Windows +!! description STR_BASEGRAPHICS_WIN_DESCRIPTION + +[files] +base = TRG1R.GRF +logos = TRGIR.GRF +arctic = TRGCR.GRF +tropical = TRGHR.GRF +toyland = TRGTR.GRF +extra = OPENTTD.GRF + +[md5s] +TRG1R.GRF = b04ce593d8c5016e07473a743d7d3358 +TRGIR.GRF = 0c2484ff6be49fc63a83be6ab5c38f32 +TRGCR.GRF = 3668f410c761a050b5e7095a2b14879b +TRGHR.GRF = 06bf2b7a31766f048baac2ebe43457b1 +TRGTR.GRF = de53650517fe661ceaa3138c6edb0eb8 +OPENTTD.GRF = + +[origin] +default = You can find it on your Transport Tycoon Deluxe CD-ROM. +OPENTTD.GRF = This file was part of your OpenTTD installation. diff --git a/media/baseset/orig_win.obm b/media/baseset/orig_win.obm new file mode 100644 index 0000000..8b35b6d --- /dev/null +++ b/media/baseset/orig_win.obm @@ -0,0 +1,94 @@ +; $Id$ +; +; This represents the original music as on the Transport +; Tycoon Deluxe for Windows CD. +; +[metadata] +name = original_windows +shortname = TTDW +version = 1 +!! description STR_BASEMUSIC_WIN_DESCRIPTION + +[files] +theme = GM_TT00.GM +old_0 = GM_TT02.GM +old_1 = GM_TT06.GM +old_2 = GM_TT03.GM +old_3 = GM_TT12.GM +old_4 = GM_TT08.GM +old_5 = GM_TT13.GM +old_6 = GM_TT14.GM +old_7 = GM_TT10.GM +old_8 = +old_9 = +new_0 = GM_TT04.GM +new_1 = GM_TT01.GM +new_2 = GM_TT05.GM +new_3 = GM_TT15.GM +new_4 = GM_TT11.GM +new_5 = GM_TT16.GM +new_6 = GM_TT09.GM +new_7 = +new_8 = +new_9 = +ezy_0 = GM_TT18.GM +ezy_1 = GM_TT19.GM +ezy_2 = GM_TT21.GM +ezy_3 = GM_TT17.GM +ezy_4 = GM_TT20.GM +ezy_5 = GM_TT07.GM +ezy_6 = +ezy_7 = +ezy_8 = +ezy_9 = + +[md5s] +GM_TT00.GM = 45cfec1b9d8c7a0ad45e755833cbf221 +GM_TT01.GM = ab14ed3392d848abd2a2e90a9d75d121 +GM_TT02.GM = dd4f696e4be5987ce738257b08b50171 +GM_TT03.GM = a1bfde23343df9e4063419bf29c166b8 +GM_TT04.GM = 4e6943aa0c455203d76c79389054747d +GM_TT05.GM = cee281cb85a2e2343552d97640545a47 +GM_TT06.GM = 26d1de5efa8675f94065784e9d539e49 +GM_TT07.GM = 6f2691e17558f552ec4c565e4ab7139c +GM_TT08.GM = a42bf2cb3340a822f1a69646fc7a487d +GM_TT09.GM = eb35761a58a8df3c59ed8929cce13916 +GM_TT10.GM = 42fecd686720a785d20a78590c466a82 +GM_TT11.GM = 50ef1ef02e49d2112786dd45e69dc3ee +GM_TT12.GM = 4ce707a0e0e72419f0681dd9bd95271b +GM_TT13.GM = e765753be29d889ec818f38009103619 +GM_TT14.GM = 270e2d63bd32b95a4d007ce15a6ce45f +GM_TT15.GM = 89e116a1c0c69f1845cc903a9bfbe460 +GM_TT16.GM = f824e2371b3bedfe61aad4b9c62dd6be +GM_TT17.GM = 1b23eebb0796c1ab99cd97fa7082cf7b +GM_TT18.GM = 15650de3bad645d0e88c4f5c7a2df92a +GM_TT19.GM = 7aec079e15bd09588660b85545ac4dfc +GM_TT20.GM = 1509097889dee617aa1e9a1738a5a930 +GM_TT21.GM = a8d0aaad02e1a762d8d54cf81da56bab + +[names] +GM_TT00.GM = Tycoon DELUXE Theme +GM_TT01.GM = Snarl Up +GM_TT02.GM = Easy Driver +GM_TT03.GM = Little Red Diesel +GM_TT04.GM = City Groove +GM_TT05.GM = Aliens Ate My Railway +GM_TT06.GM = Stoke It +GM_TT07.GM = Don't Walk! +GM_TT08.GM = Sawyer's Tune +GM_TT09.GM = Fell Apart On Me +GM_TT10.GM = Can't Get There From Here +GM_TT11.GM = Hard Drivin' +GM_TT12.GM = Road Hog +GM_TT13.GM = Hold That Train! +GM_TT14.GM = Broomer's Oil Rag +GM_TT15.GM = Goss Groove +GM_TT16.GM = Small Town +GM_TT17.GM = Cruise Control +GM_TT18.GM = Stroll On +GM_TT19.GM = Funk Central +GM_TT20.GM = Jammit +GM_TT21.GM = Movin' On + +[origin] +default = You can find it on your Transport Tycoon Deluxe CD-ROM. diff --git a/media/baseset/orig_win.obs b/media/baseset/orig_win.obs new file mode 100644 index 0000000..e1c2c4e --- /dev/null +++ b/media/baseset/orig_win.obs @@ -0,0 +1,19 @@ +; $Id$ +; +; This represents the original sounds as on the Transport +; Tycoon Deluxe for Windows CD. +; +[metadata] +name = original_windows +shortname = TTDO +version = 0 +!! description STR_BASESOUNDS_WIN_DESCRIPTION + +[files] +samples = SAMPLE.CAT + +[md5s] +SAMPLE.CAT = 9212e81e72badd4bbe1eaeae66458e10 + +[origin] +default = You can find it on your Transport Tycoon Deluxe CD-ROM. diff --git a/media/baseset/translations.awk b/media/baseset/translations.awk new file mode 100644 index 0000000..f15cb43 --- /dev/null +++ b/media/baseset/translations.awk @@ -0,0 +1,69 @@ +# $Id: openttd.desktop.translation.awk 24100 2012-04-08 14:29:31Z rubidium $ + +# This file is part of OpenTTD. +# OpenTTD 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, version 2. +# OpenTTD 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 OpenTTD. If not, see . + +# +# Awk script to extract translations for baseset descriptions +# from lang files for insertion into .obg/obs/obm files. +# If there is no translation, there is no output. +# +# The input file is scanned for the pattern +# !! +# +# The lang files (passed as variable 'langfiles') are scanned for and +# the translations are added to the output file: +# . = +# + +# Simple insertion sort since not all AWKs have a sort implementation +function isort(A) { + n = 0 + for (val in A) { + n++; + } + + for (i = 2; i <= n; i++) { + j = i; + hold = A[j] + while (A[j - 1] > hold) { + j--; + A[j + 1] = A[j] + } + A[j] = hold + } + + return n +} + +/^!!/ { + ini_key = $2; + str_id = $3; + + file = langfiles + while ((getline < file) > 0) { + if (match($0, "##isocode") > 0) { + lang = $2; + } else if (match($0, "^" str_id " *:") > 0) { + sub("^[^:]*:", "", $0) + i++; + if (lang == "en_GB") { + texts[i] = ini_key " = "$0; + } else { + texts[i] = ini_key "." lang " = "$0; + } + } + } + close(file); + + count = isort(texts); + for (i = 1; i <= count; i++) { + print texts[i] + } + + next +} + +{ print } diff --git a/media/extra_grf/2ccmap.nfo b/media/extra_grf/2ccmap.nfo new file mode 100644 index 0000000..0e99ff8 --- /dev/null +++ b/media/extra_grf/2ccmap.nfo @@ -0,0 +1,2316 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// +// This is the DOS 2CC translation map which OpenTTD translates if needed upon loading. +// + -1 * 0 0C "2CC map" + -1 * 0 05 0A FF 00 01 + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF + -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E + 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E + 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E + 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E + 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E + 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE + BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE + DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE + FF diff --git a/media/extra_grf/airport_preview.nfo b/media/extra_grf/airport_preview.nfo new file mode 100644 index 0000000..a98fe67 --- /dev/null +++ b/media/extra_grf/airport_preview.nfo @@ -0,0 +1,19 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// + -1 * 0 0C "Airport previews" + -1 * 0 05 16 09 + -1 sprites/airport_preview.png 8bpp 50 8 230 140 0 0 normal + -1 sprites/airport_preview.png 8bpp 290 8 230 140 0 0 normal + -1 sprites/airport_preview.png 8bpp 530 8 230 140 0 0 normal + -1 sprites/airport_preview.png 8bpp 2 168 230 140 0 0 normal + -1 sprites/airport_preview.png 8bpp 242 168 230 140 0 0 normal + -1 sprites/airport_preview.png 8bpp 482 168 230 140 0 0 normal + -1 sprites/airport_preview.png 8bpp 2 328 230 140 0 0 normal + -1 sprites/airport_preview.png 8bpp 242 328 230 140 0 0 normal + -1 sprites/airport_preview.png 8bpp 482 328 230 140 0 0 normal diff --git a/media/extra_grf/airport_preview.png b/media/extra_grf/airport_preview.png new file mode 100644 index 0000000..cfa41f2 Binary files /dev/null and b/media/extra_grf/airport_preview.png differ diff --git a/media/extra_grf/airports.nfo b/media/extra_grf/airports.nfo new file mode 100644 index 0000000..8feb813 --- /dev/null +++ b/media/extra_grf/airports.nfo @@ -0,0 +1,25 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// + -1 * 0 0C "Extra airport graphics" + -1 * 3 05 10 0F + -1 sprites/airports.png 8bpp 18 8 64 31 -31 0 normal + -1 sprites/airports.png 8bpp 98 8 64 31 -31 0 normal + -1 sprites/airports.png 8bpp 178 8 64 31 -31 0 normal + -1 sprites/airports.png 8bpp 258 8 64 31 -31 0 normal + -1 sprites/airports.png 8bpp 338 8 64 31 -31 0 normal + -1 sprites/airports.png 8bpp 418 8 64 31 -31 0 normal + -1 sprites/airports.png 8bpp 498 8 64 55 -2 -38 normal + -1 sprites/airports.png 8bpp 578 8 18 17 16 -1 normal + -1 sprites/airports.png 8bpp 610 8 64 55 -2 -38 normal + -1 sprites/airports.png 8bpp 690 8 18 17 -30 1 normal + -1 sprites/airports.png 8bpp 722 8 64 55 -2 -38 normal + -1 sprites/airports.png 8bpp 2 88 64 55 -2 -38 normal + -1 sprites/airports.png 8bpp 82 88 64 31 -31 0 normal + -1 sprites/airports.png 8bpp 162 88 64 31 -31 0 normal + -1 sprites/airports.png 8bpp 242 88 64 31 -31 0 normal diff --git a/media/extra_grf/airports.png b/media/extra_grf/airports.png new file mode 100644 index 0000000..fd63355 Binary files /dev/null and b/media/extra_grf/airports.png differ diff --git a/media/extra_grf/aqueduct.nfo b/media/extra_grf/aqueduct.nfo new file mode 100644 index 0000000..d9ba739 --- /dev/null +++ b/media/extra_grf/aqueduct.nfo @@ -0,0 +1,31 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// + -1 * 0 0C "Aqueduct graphics by Jonathan G. Rennison / PaulC" +// temperate aqueduct + -1 * 6 07 83 01 \7! 00 09 + -1 * 3 05 12 08 + -1 sprites/aqueduct.png 8bpp 34 8 61 32 -30 -9 normal + -1 sprites/aqueduct.png 8bpp 114 8 62 31 -29 -9 normal + -1 sprites/aqueduct.png 8bpp 194 8 61 32 -30 -9 normal + -1 sprites/aqueduct.png 8bpp 274 8 62 31 -29 -9 normal + -1 sprites/aqueduct.png 8bpp 354 8 61 32 -30 -4 normal + -1 sprites/aqueduct.png 8bpp 434 8 62 31 -29 -4 normal + -1 sprites/aqueduct.png 8bpp 514 8 33 23 -31 0 normal + -1 sprites/aqueduct.png 8bpp 562 8 33 23 0 1 normal +// non-temperate aqueduct + -1 * 6 07 83 01 \7= 00 09 + -1 * 3 05 12 08 + -1 sprites/aqueduct.png 8bpp 34 48 61 32 -30 -9 normal + -1 sprites/aqueduct.png 8bpp 114 48 62 31 -29 -9 normal + -1 sprites/aqueduct.png 8bpp 194 48 61 32 -30 -9 normal + -1 sprites/aqueduct.png 8bpp 274 48 62 31 -29 -9 normal + -1 sprites/aqueduct.png 8bpp 354 48 61 32 -30 -4 normal + -1 sprites/aqueduct.png 8bpp 434 48 62 31 -29 -4 normal + -1 sprites/aqueduct.png 8bpp 514 48 33 23 -31 0 normal + -1 sprites/aqueduct.png 8bpp 562 48 33 23 0 1 normal diff --git a/media/extra_grf/aqueduct.png b/media/extra_grf/aqueduct.png new file mode 100644 index 0000000..6d55f0a Binary files /dev/null and b/media/extra_grf/aqueduct.png differ diff --git a/media/extra_grf/assemble_nfo.awk b/media/extra_grf/assemble_nfo.awk new file mode 100644 index 0000000..cf6b425 --- /dev/null +++ b/media/extra_grf/assemble_nfo.awk @@ -0,0 +1,32 @@ +# $Id$ + +# This file is part of OpenTTD. +# OpenTTD 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, version 2. +# OpenTTD 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 OpenTTD. If not, see . + +BEGIN { + # Very basic variant function; barely any error checking. + # Just use the first argument as the file to start from when assembling everything + path = ARGV[1]; + gsub("[^/\\\\]*$", "", path); + assemble(ARGV[1]); +} + +# Recursive function for assembling by means of resolving the #includes. +function assemble(filename) { + while ((getline < filename) > 0) { + if (NF == 2 && $1 == "#include" ) { + # Remove the quotes. + gsub("[\"'<>]", "", $2); + assemble(path $2); + } else { + print $0; + } + } + + if (close(filename) < 0) { + print "Could not open " filename > "/dev/stderr"; + exit -1; + } +} diff --git a/media/extra_grf/autorail.nfo b/media/extra_grf/autorail.nfo new file mode 100644 index 0000000..08aa5ef --- /dev/null +++ b/media/extra_grf/autorail.nfo @@ -0,0 +1,65 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// + -1 * 0 0C "Autorail graphics" + -1 * 3 05 13 37 + -1 sprites/autorail.png 8bpp 18 8 64 31 -31 7 normal + -1 sprites/autorail.png 8bpp 98 8 64 31 -31 -1 normal + -1 sprites/autorail.png 8bpp 178 8 64 39 -31 -1 normal + -1 sprites/autorail.png 8bpp 258 8 64 47 -31 -9 normal + -1 sprites/autorail.png 8bpp 338 8 64 31 -31 -5 normal + -1 sprites/autorail.png 8bpp 418 8 64 23 -31 7 normal + -1 sprites/autorail.png 8bpp 498 8 64 18 -31 4 normal + -1 sprites/autorail.png 8bpp 578 8 64 31 -31 -1 normal + -1 sprites/autorail.png 8bpp 658 8 64 31 -31 7 normal + -1 sprites/autorail.png 8bpp 2 72 64 31 -31 -1 normal + -1 sprites/autorail.png 8bpp 82 72 64 23 -31 7 normal + -1 sprites/autorail.png 8bpp 162 72 64 18 -31 4 normal + -1 sprites/autorail.png 8bpp 242 72 64 31 -31 -1 normal + -1 sprites/autorail.png 8bpp 322 72 64 39 -31 -1 normal + -1 sprites/autorail.png 8bpp 402 72 64 47 -31 -9 normal + -1 sprites/autorail.png 8bpp 482 72 64 31 -31 -5 normal + -1 sprites/autorail.png 8bpp 562 72 64 31 -31 7 normal + -1 sprites/autorail.png 8bpp 642 72 64 31 -31 -1 normal + -1 sprites/autorail.png 8bpp 722 72 64 47 -31 -9 normal + -1 sprites/autorail.png 8bpp 2 136 64 26 -31 4 normal + -1 sprites/autorail.png 8bpp 82 136 64 23 -31 4 normal + -1 sprites/autorail.png 8bpp 162 136 64 31 -31 -3 normal + -1 sprites/autorail.png 8bpp 242 136 64 26 -31 4 normal + -1 sprites/autorail.png 8bpp 322 136 64 23 -31 4 normal + -1 sprites/autorail.png 8bpp 402 136 64 31 -31 -3 normal + -1 sprites/autorail.png 8bpp 482 136 64 31 -31 7 normal + -1 sprites/autorail.png 8bpp 562 136 64 31 -31 -1 normal + -1 sprites/autorail.png 8bpp 642 136 64 15 -31 7 normal + -1 sprites/autorail.png 8bpp 722 136 64 31 -31 7 normal + -1 sprites/autorail.png 8bpp 2 184 64 39 -31 -1 normal + -1 sprites/autorail.png 8bpp 82 184 64 31 -31 -1 normal + -1 sprites/autorail.png 8bpp 162 184 64 31 -31 7 normal + -1 sprites/autorail.png 8bpp 242 184 64 39 -31 -1 normal + -1 sprites/autorail.png 8bpp 322 184 64 31 -31 -1 normal + -1 sprites/autorail.png 8bpp 402 184 64 31 -31 7 normal + -1 sprites/autorail.png 8bpp 482 184 64 31 -31 -1 normal + -1 sprites/autorail.png 8bpp 562 184 64 31 -31 -1 normal + -1 sprites/autorail.png 8bpp 642 184 64 31 -31 -1 normal + -1 sprites/autorail.png 8bpp 722 184 64 23 -31 7 normal + -1 sprites/autorail.png 8bpp 2 248 64 15 -31 7 normal + -1 sprites/autorail.png 8bpp 82 248 64 39 -31 -1 normal + -1 sprites/autorail.png 8bpp 162 248 64 47 -31 -9 normal + -1 sprites/autorail.png 8bpp 242 248 64 31 -31 7 normal + -1 sprites/autorail.png 8bpp 322 248 64 31 -31 -1 normal + -1 sprites/autorail.png 8bpp 402 248 64 31 -31 -1 normal + -1 sprites/autorail.png 8bpp 482 248 64 31 -31 -1 normal + -1 sprites/autorail.png 8bpp 562 248 64 23 -31 7 normal + -1 sprites/autorail.png 8bpp 642 248 64 15 -31 7 normal + -1 sprites/autorail.png 8bpp 722 248 64 39 -31 -1 normal + -1 sprites/autorail.png 8bpp 2 312 64 47 -31 -9 normal + -1 sprites/autorail.png 8bpp 82 312 64 31 -31 -1 normal + -1 sprites/autorail.png 8bpp 162 312 64 31 -31 -1 normal + -1 sprites/autorail.png 8bpp 242 312 64 23 -31 7 normal + -1 sprites/autorail.png 8bpp 322 312 64 31 -31 7 normal + -1 sprites/autorail.png 8bpp 402 312 64 31 -31 7 normal diff --git a/media/extra_grf/autorail.png b/media/extra_grf/autorail.png new file mode 100644 index 0000000..5c21d36 Binary files /dev/null and b/media/extra_grf/autorail.png differ diff --git a/media/extra_grf/canal_locks.png b/media/extra_grf/canal_locks.png new file mode 100644 index 0000000..f156402 Binary files /dev/null and b/media/extra_grf/canal_locks.png differ diff --git a/media/extra_grf/canals.nfo b/media/extra_grf/canals.nfo new file mode 100644 index 0000000..c0d0275 --- /dev/null +++ b/media/extra_grf/canals.nfo @@ -0,0 +1,171 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// + -1 * 0 0C "Canal graphics by George / PaulC" + -1 * 3 05 08 41 +// Canal slopes + -1 sprites/canal_locks.png 8bpp 66 8 64 23 -31 0 normal + -1 sprites/canal_locks.png 8bpp 146 8 64 39 -31 -8 normal + -1 sprites/canal_locks.png 8bpp 226 8 64 23 -31 0 normal + -1 sprites/canal_locks.png 8bpp 306 8 64 39 -31 -8 normal +// Lock sides + -1 sprites/canal_locks.png 8bpp 386 8 40 26 -7 -12 normal + -1 sprites/canal_locks.png 8bpp 434 8 42 33 -31 -13 normal + -1 sprites/canal_locks.png 8bpp 482 8 40 25 -31 -12 normal + -1 sprites/canal_locks.png 8bpp 530 8 42 34 -9 -14 normal + -1 sprites/canal_locks.png 8bpp 578 8 32 27 -1 -17 normal + -1 sprites/canal_locks.png 8bpp 626 8 32 35 -29 -17 normal + -1 sprites/canal_locks.png 8bpp 674 8 32 27 -29 -17 normal + -1 sprites/canal_locks.png 8bpp 722 8 32 35 -1 -17 normal + -1 sprites/canal_locks.png 8bpp 2 72 40 44 -7 -24 normal + -1 sprites/canal_locks.png 8bpp 50 72 42 33 -31 -13 normal + -1 sprites/canal_locks.png 8bpp 98 72 40 32 -31 -12 normal + -1 sprites/canal_locks.png 8bpp 146 72 41 31 -8 -12 normal + -1 sprites/canal_locks.png 8bpp 194 72 34 32 -1 -13 normal + -1 sprites/canal_locks.png 8bpp 242 72 38 34 -35 -17 normal + -1 sprites/canal_locks.png 8bpp 290 72 34 44 -29 -26 normal + -1 sprites/canal_locks.png 8bpp 338 72 38 34 -1 -17 normal + -1 sprites/canal_locks.png 8bpp 386 72 42 24 -9 -4 normal + -1 sprites/canal_locks.png 8bpp 434 72 43 24 -31 -4 normal + -1 sprites/canal_locks.png 8bpp 482 72 53 24 -31 -4 normal + -1 sprites/canal_locks.png 8bpp 546 72 43 37 -10 -16 normal + -1 sprites/canal_locks.png 8bpp 594 72 38 26 -1 -9 normal + -1 sprites/canal_locks.png 8bpp 642 72 34 37 -29 -18 normal + -1 sprites/canal_locks.png 8bpp 690 72 38 26 -35 -9 normal + -1 sprites/canal_locks.png 8bpp 738 72 32 23 -1 -5 normal + -1 sprites/canal_locks.png 8bpp 2 136 40 26 -7 -12 normal + -1 sprites/canal_locks.png 8bpp 50 136 42 33 -31 -13 normal + -1 sprites/canal_locks.png 8bpp 98 136 40 25 -31 -12 normal + -1 sprites/canal_locks.png 8bpp 146 136 42 34 -9 -14 normal + -1 sprites/canal_locks.png 8bpp 194 136 32 27 -1 -17 normal + -1 sprites/canal_locks.png 8bpp 242 136 32 35 -29 -17 normal + -1 sprites/canal_locks.png 8bpp 290 136 32 27 -29 -17 normal + -1 sprites/canal_locks.png 8bpp 338 136 32 35 -1 -17 normal + -1 sprites/canal_locks.png 8bpp 386 136 40 32 -7 -12 normal + -1 sprites/canal_locks.png 8bpp 434 136 42 33 -31 -13 normal + -1 sprites/canal_locks.png 8bpp 482 136 40 32 -31 -12 normal + -1 sprites/canal_locks.png 8bpp 530 136 41 31 -8 -12 normal + -1 sprites/canal_locks.png 8bpp 578 136 34 32 -1 -13 normal + -1 sprites/canal_locks.png 8bpp 626 136 38 34 -35 -17 normal + -1 sprites/canal_locks.png 8bpp 674 136 34 32 -29 -14 normal + -1 sprites/canal_locks.png 8bpp 722 136 38 34 -1 -17 normal + -1 sprites/canal_locks.png 8bpp 2 184 42 24 -9 -4 normal + -1 sprites/canal_locks.png 8bpp 50 184 43 24 -31 -4 normal + -1 sprites/canal_locks.png 8bpp 98 184 53 24 -31 -4 normal + -1 sprites/canal_locks.png 8bpp 162 184 43 25 -10 -4 normal + -1 sprites/canal_locks.png 8bpp 210 184 38 26 -1 -9 normal + -1 sprites/canal_locks.png 8bpp 258 184 34 25 -29 -6 normal + -1 sprites/canal_locks.png 8bpp 306 184 38 26 -35 -9 normal + -1 sprites/canal_locks.png 8bpp 354 184 32 23 -1 -5 normal +// Canal edges (temperate) + -1 sprites/canals.png 8bpp 30 10 45 22 -11 -1 normal + -1 sprites/canals.png 8bpp 94 10 41 21 -8 10 normal + -1 sprites/canals.png 8bpp 142 10 42 21 -31 10 normal + -1 sprites/canals.png 8bpp 190 10 43 22 -31 -1 normal + -1 sprites/canals.png 8bpp 238 10 22 22 11 4 normal + -1 sprites/canals.png 8bpp 270 10 24 16 -11 15 normal + -1 sprites/canals.png 8bpp 302 10 23 23 -31 4 normal + -1 sprites/canals.png 8bpp 334 10 24 18 -11 -1 normal + -1 sprites/canals.png 8bpp 366 10 12 11 21 10 normal + -1 sprites/canals.png 8bpp 398 10 19 10 -8 21 normal + -1 sprites/canals.png 8bpp 430 10 11 10 -31 10 normal + -1 sprites/canals.png 8bpp 446 10 24 16 -11 -6 normal +// Canal icon + -1 sprites/canal_locks.png 8bpp 50 232 20 20 0 0 normal + +// Differentiation for the climates starts here + +// Canal edges (arctic snowy) + -1 * 4 01 05 01 \b12 + -1 sprites/canals.png 8bpp 30 40 45 22 -11 -1 normal + -1 sprites/canals.png 8bpp 94 40 41 21 -8 10 normal + -1 sprites/canals.png 8bpp 142 40 42 21 -31 10 normal + -1 sprites/canals.png 8bpp 190 40 43 22 -31 -1 normal + -1 sprites/canals.png 8bpp 238 40 22 22 11 4 normal + -1 sprites/canals.png 8bpp 270 40 24 16 -11 15 normal + -1 sprites/canals.png 8bpp 302 40 23 23 -31 4 normal + -1 sprites/canals.png 8bpp 334 40 24 18 -11 -1 normal + -1 sprites/canals.png 8bpp 366 40 12 11 21 10 normal + -1 sprites/canals.png 8bpp 398 40 19 10 -8 21 normal + -1 sprites/canals.png 8bpp 430 40 11 10 -31 10 normal + -1 sprites/canals.png 8bpp 446 40 24 16 -11 -6 normal + -1 * 7 02 05 10 01 00 00 00 + +// Canal edges (arctic normal) + -1 * 4 01 05 01 \b12 + -1 sprites/canals.png 8bpp 30 70 45 22 -11 -1 normal + -1 sprites/canals.png 8bpp 94 70 41 21 -8 10 normal + -1 sprites/canals.png 8bpp 142 70 42 21 -31 10 normal + -1 sprites/canals.png 8bpp 190 70 43 22 -31 -1 normal + -1 sprites/canals.png 8bpp 238 70 22 22 11 4 normal + -1 sprites/canals.png 8bpp 270 70 24 16 -11 15 normal + -1 sprites/canals.png 8bpp 302 70 23 23 -31 4 normal + -1 sprites/canals.png 8bpp 334 70 24 18 -11 -1 normal + -1 sprites/canals.png 8bpp 366 70 12 11 21 10 normal + -1 sprites/canals.png 8bpp 398 70 19 10 -8 21 normal + -1 sprites/canals.png 8bpp 430 70 11 10 -31 10 normal + -1 sprites/canals.png 8bpp 446 70 24 16 -11 -6 normal + -1 * 7 02 05 11 01 00 00 00 +// Choose the right arctic canal edges + -1 * 14 02 05 12 81 81 00 FF 01 10 00 04 04 11 00 + -1 * 6 07 83 01 \7! 01 01 + -1 * 7 03 05 01 02 00 12 00 + +// Canal edges (tropic desert) + -1 * 4 01 05 01 \b12 + -1 sprites/canals.png 8bpp 30 100 45 22 -11 -1 normal + -1 sprites/canals.png 8bpp 94 100 41 21 -8 10 normal + -1 sprites/canals.png 8bpp 142 100 42 21 -31 10 normal + -1 sprites/canals.png 8bpp 190 100 43 22 -31 -1 normal + -1 sprites/canals.png 8bpp 238 100 22 22 11 4 normal + -1 sprites/canals.png 8bpp 270 100 24 16 -11 15 normal + -1 sprites/canals.png 8bpp 302 100 23 23 -31 4 normal + -1 sprites/canals.png 8bpp 334 100 24 18 -11 -1 normal + -1 sprites/canals.png 8bpp 366 100 12 11 21 10 normal + -1 sprites/canals.png 8bpp 398 100 19 10 -8 21 normal + -1 sprites/canals.png 8bpp 430 100 11 10 -31 10 normal + -1 sprites/canals.png 8bpp 446 100 24 16 -11 -6 normal + -1 * 7 02 05 13 01 00 00 00 + +// Canal edges (tropic rainforest) + -1 * 4 01 05 01 \b12 + -1 sprites/canals.png 8bpp 30 130 45 22 -11 -1 normal + -1 sprites/canals.png 8bpp 94 130 41 21 -8 10 normal + -1 sprites/canals.png 8bpp 142 130 42 21 -31 10 normal + -1 sprites/canals.png 8bpp 190 130 43 22 -31 -1 normal + -1 sprites/canals.png 8bpp 238 130 22 22 11 4 normal + -1 sprites/canals.png 8bpp 270 130 24 16 -11 15 normal + -1 sprites/canals.png 8bpp 302 130 23 23 -31 4 normal + -1 sprites/canals.png 8bpp 334 130 24 18 -11 -1 normal + -1 sprites/canals.png 8bpp 366 130 12 11 21 10 normal + -1 sprites/canals.png 8bpp 398 130 19 10 -8 21 normal + -1 sprites/canals.png 8bpp 430 130 11 10 -31 10 normal + -1 sprites/canals.png 8bpp 446 130 24 16 -11 -6 normal + -1 * 7 02 05 14 01 00 00 00 +// Choose the right tropic canal edges + -1 * 14 02 05 15 81 81 00 FF 01 13 00 01 01 14 00 + -1 * 6 07 83 01 \7! 02 01 + -1 * 7 03 05 01 02 00 15 00 + +// Canal edges (toyland) + -1 * 4 01 05 01 \b12 + -1 sprites/canals.png 8bpp 30 160 45 22 -11 -1 normal + -1 sprites/canals.png 8bpp 94 160 41 21 -8 10 normal + -1 sprites/canals.png 8bpp 142 160 42 21 -31 10 normal + -1 sprites/canals.png 8bpp 190 160 43 22 -31 -1 normal + -1 sprites/canals.png 8bpp 238 160 22 22 11 4 normal + -1 sprites/canals.png 8bpp 270 160 24 16 -11 15 normal + -1 sprites/canals.png 8bpp 302 160 23 23 -31 4 normal + -1 sprites/canals.png 8bpp 334 160 24 18 -11 -1 normal + -1 sprites/canals.png 8bpp 366 160 12 11 21 10 normal + -1 sprites/canals.png 8bpp 398 160 19 10 -8 21 normal + -1 sprites/canals.png 8bpp 430 160 11 10 -31 10 normal + -1 sprites/canals.png 8bpp 446 160 24 16 -11 -6 normal + -1 * 7 02 05 16 01 00 00 00 + -1 * 6 07 83 01 \7! 03 01 + -1 * 7 03 05 01 02 00 16 00 diff --git a/media/extra_grf/canals.png b/media/extra_grf/canals.png new file mode 100644 index 0000000..f9f6da6 Binary files /dev/null and b/media/extra_grf/canals.png differ diff --git a/media/extra_grf/chars.nfo b/media/extra_grf/chars.nfo new file mode 100644 index 0000000..26db641 --- /dev/null +++ b/media/extra_grf/chars.nfo @@ -0,0 +1,1083 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// + -1 * 0 0C "Font characters by PaulC, Bilbo and Jasper Vries" + +// Replace original characters + + -1 * 5 0A 01 02 41 00 + -1 sprites/chars.png 8bpp 10 10 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 20 10 4 12 0 -1 normal + -1 * 5 0A 01 02 86 00 + -1 sprites/chars.png 8bpp 50 10 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 70 10 9 12 0 -1 normal + -1 * 5 0A 01 01 8A 00 + -1 sprites/chars.png 8bpp 120 10 6 12 0 -1 normal + -1 * 5 0A 01 01 A0 00 + -1 sprites/chars.png 8bpp 230 10 10 12 0 -1 normal + -1 * 5 0A 01 04 A2 00 + -1 sprites/chars.png 8bpp 260 10 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 290 10 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 320 10 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 350 10 8 12 0 -1 normal + -1 * 5 0A 01 06 A7 00 + -1 sprites/chars.png 8bpp 410 10 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 440 10 12 12 0 -1 normal + -1 sprites/chars.png 8bpp 470 10 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 480 10 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 500 10 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 520 10 7 12 0 -1 normal + -1 * 5 0A 01 03 AE 00 + -1 sprites/chars.png 8bpp 560 10 4 12 0 -1 normal + -1 sprites/chars.png 8bpp 570 10 4 12 0 -1 normal + -1 sprites/chars.png 8bpp 580 10 5 12 0 -1 normal + -1 * 5 0A 01 05 B3 00 + -1 sprites/chars.png 8bpp 620 10 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 640 10 9 12 0 -1 normal + -1 sprites/chars.png 8bpp 660 10 9 12 0 -1 normal + -1 sprites/chars.png 8bpp 680 10 9 12 0 -1 normal + -1 sprites/chars.png 8bpp 700 10 9 12 0 -1 normal + -1 * 5 0A 01 03 BB 00 + -1 sprites/chars.png 8bpp 770 10 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 10 70 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 30 70 8 12 0 -1 normal + -1 * 5 0A 01 01 BF 00 + -1 sprites/chars.png 8bpp 70 70 9 12 0 -1 normal + -1 * 5 0A 01 05 C1 00 + -1 sprites/chars.png 8bpp 450 70 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 110 70 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 120 70 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 130 70 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 140 70 6 12 0 -1 normal + -1 * 5 0A 01 01 C7 00 + -1 sprites/chars.png 8bpp 160 70 6 12 0 -1 normal + -1 * 5 0A 01 03 CA 00 + -1 sprites/chars.png 8bpp 200 70 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 210 70 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 220 70 6 12 0 -1 normal + -1 * 5 0A 01 04 CE 00 + -1 sprites/chars.png 8bpp 230 70 4 12 0 -1 normal + -1 sprites/chars.png 8bpp 240 70 4 12 0 -1 normal + -1 sprites/chars.png 8bpp 250 70 5 12 0 -1 normal + -1 sprites/chars.png 8bpp 260 70 5 12 0 -1 normal + -1 * 5 0A 01 05 D3 00 + -1 sprites/chars.png 8bpp 290 70 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 310 70 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 320 70 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 330 70 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 340 70 6 12 0 -1 normal + -1 * 5 0A 01 03 DB 00 + -1 sprites/chars.png 8bpp 390 70 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 400 70 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 410 70 6 12 0 -1 normal + -1 * 5 0A 01 02 DF 00 + -1 sprites/chars.png 8bpp 420 70 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 430 70 6 12 0 -1 normal + -1 * 5 0A 01 01 22 01 + -1 sprites/chars.png 8bpp 20 30 2 7 0 0 normal + -1 * 5 0A 01 01 7D 01 + -1 sprites/chars.png 8bpp 220 30 4 7 0 0 normal + -1 * 5 0A 01 02 80 01 + -1 sprites/chars.png 8bpp 230 30 9 7 0 0 normal + -1 sprites/chars.png 8bpp 250 30 3 7 0 0 normal + -1 * 5 0A 01 01 89 01 + -1 sprites/chars.png 8bpp 470 30 3 7 0 0 normal + -1 * 5 0A 01 01 9F 01 + -1 sprites/chars.png 8bpp 70 90 3 7 0 0 normal + -1 * 5 0A 01 01 A9 01 + -1 sprites/chars.png 8bpp 190 90 3 7 0 0 normal + -1 * 5 0A 01 02 BF 01 + -1 sprites/chars.png 8bpp 420 90 3 7 0 0 normal + -1 sprites/chars.png 8bpp 430 90 3 7 0 0 normal + -1 * 5 0A 01 01 02 02 + -1 sprites/chars.png 8bpp 20 40 4 21 0 -2 normal + -1 * 5 0A 01 01 41 02 + -1 sprites/chars.png 8bpp 30 40 14 21 0 -2 normal + -1 * 5 0A 01 06 46 02 + -1 sprites/chars.png 8bpp 50 40 10 21 0 -2 normal + -1 sprites/chars.png 8bpp 70 40 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 90 40 3 21 0 -2 normal + -1 sprites/chars.png 8bpp 100 40 13 21 0 -2 normal + -1 sprites/chars.png 8bpp 120 40 7 21 0 -2 normal + -1 sprites/chars.png 8bpp 130 40 16 21 0 -2 normal + -1 * 5 0A 01 01 50 02 + -1 sprites/chars.png 8bpp 150 40 16 21 0 -2 normal + -1 * 5 0A 01 04 52 02 + -1 sprites/chars.png 8bpp 170 40 8 21 0 -2 normal + -1 sprites/chars.png 8bpp 180 40 9 21 0 -2 normal + -1 sprites/chars.png 8bpp 190 40 6 21 0 -2 normal + -1 sprites/chars.png 8bpp 200 40 6 21 0 -2 normal + -1 * 5 0A 01 01 5C 02 + -1 sprites/chars.png 8bpp 210 40 7 21 0 -2 normal + -1 * 5 0A 01 01 60 02 + -1 sprites/chars.png 8bpp 230 40 16 21 0 -2 normal + -1 * 5 0A 01 07 62 02 + -1 sprites/chars.png 8bpp 260 40 20 21 0 -2 normal + -1 sprites/chars.png 8bpp 290 40 20 21 0 -2 normal + -1 sprites/chars.png 8bpp 320 40 20 21 0 -2 normal + -1 sprites/chars.png 8bpp 350 40 20 21 0 -2 normal + -1 sprites/chars.png 8bpp 380 40 20 21 0 -2 normal + -1 sprites/chars.png 8bpp 410 40 20 21 0 -2 normal + -1 sprites/chars.png 8bpp 440 40 24 21 0 -2 normal + -1 * 5 0A 01 18 6A 02 + -1 sprites/chars.png 8bpp 480 40 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 500 40 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 520 40 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 540 40 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 560 40 9 21 0 -2 normal + -1 sprites/chars.png 8bpp 570 40 9 21 0 -2 normal + -1 sprites/chars.png 8bpp 580 40 9 21 0 -2 normal + -1 sprites/chars.png 8bpp 590 40 9 21 0 -2 normal + -1 sprites/chars.png 8bpp 600 40 17 21 0 -2 normal + -1 sprites/chars.png 8bpp 620 40 18 21 0 -2 normal + -1 sprites/chars.png 8bpp 640 40 15 21 0 -2 normal + -1 sprites/chars.png 8bpp 660 40 15 21 0 -2 normal + -1 sprites/chars.png 8bpp 680 40 15 21 0 -2 normal + -1 sprites/chars.png 8bpp 700 40 15 21 0 -2 normal + -1 sprites/chars.png 8bpp 720 40 15 21 0 -2 normal + -1 sprites/chars.png 8bpp 740 40 9 21 0 -2 normal + -1 sprites/chars.png 8bpp 750 40 16 21 0 -2 normal + -1 sprites/chars.png 8bpp 770 40 17 21 0 -2 normal + -1 sprites/chars.png 8bpp 10 100 17 21 0 -2 normal + -1 sprites/chars.png 8bpp 30 100 17 21 0 -2 normal + -1 sprites/chars.png 8bpp 50 100 17 21 0 -2 normal + -1 sprites/chars.png 8bpp 70 100 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 90 100 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 450 100 14 21 0 -2 normal + -1 * 5 0A 01 01 85 02 + -1 sprites/chars.png 8bpp 140 100 12 21 0 -2 normal + -1 * 5 0A 01 01 88 02 + -1 sprites/chars.png 8bpp 170 100 19 21 0 -2 normal + -1 * 5 0A 01 02 92 02 + -1 sprites/chars.png 8bpp 270 100 11 21 0 -2 normal + -1 sprites/chars.png 8bpp 290 100 15 21 0 -2 normal + -1 * 5 0A 01 01 97 02 + -1 sprites/chars.png 8bpp 340 100 11 21 0 -2 normal + -1 * 5 0A 01 02 99 02 + -1 sprites/chars.png 8bpp 360 100 9 21 0 -2 normal + -1 sprites/chars.png 8bpp 370 100 11 21 0 -2 normal + -1 * 5 0A 01 01 A0 02 + -1 sprites/chars.png 8bpp 430 100 14 21 0 -2 normal + +// New characters, all fonts except monospaced + +// U+007B: Left Curly Bracket +// U+007C: Vertical Line +// U+007D: Right Curly Bracket +// U+007E: Tilde + -1 * 14 12 03 00 04 7B 00 01 04 7B 00 02 04 7B 00 + -1 sprites/chars.png 8bpp 10 130 5 12 0 -1 normal + -1 sprites/chars.png 8bpp 20 130 3 12 0 -1 normal + -1 sprites/chars.png 8bpp 30 130 5 12 0 -1 normal + -1 sprites/chars.png 8bpp 50 130 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 10 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 20 150 1 7 0 0 normal + -1 sprites/chars.png 8bpp 30 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 50 150 4 7 0 0 normal + -1 sprites/chars.png 8bpp 10 160 9 21 0 -2 normal + -1 sprites/chars.png 8bpp 20 160 3 21 0 -2 normal + -1 sprites/chars.png 8bpp 30 160 9 21 0 -2 normal + -1 sprites/chars.png 8bpp 50 160 10 21 0 -2 normal + +// U+007F: No-Break Space + -1 * 14 12 03 00 01 7F 00 01 01 7F 00 02 01 7F 00 + -1 sprites/chars.png 8bpp 70 130 2 12 0 -1 normal + -1 sprites/chars.png 8bpp 70 150 1 7 0 0 normal + -1 sprites/chars.png 8bpp 70 160 5 21 0 -2 normal + +// U+00AA: Feminine Ordinal Indicator + -1 * 14 12 03 00 01 AA 00 01 01 AA 00 02 01 AA 00 + -1 sprites/chars.png 8bpp 80 130 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 80 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 80 160 7 21 0 -2 normal + +// U+00AC: Not Sign +// U+00AD: Soft Hyphen + -1 * 14 12 03 00 02 AC 00 01 02 AC 00 02 02 AC 00 + -1 sprites/chars.png 8bpp 90 130 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 110 130 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 90 150 4 7 0 0 normal + -1 sprites/chars.png 8bpp 110 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 90 160 12 21 0 -2 normal + -1 sprites/chars.png 8bpp 110 160 9 21 0 -2 normal + +// U+00AF: Macron + -1 * 14 12 03 00 01 AF 00 01 01 AF 00 02 01 AF 00 + -1 sprites/chars.png 8bpp 130 130 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 130 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 130 160 12 21 0 -2 normal + +// U+00B4: Acute Accent +// U+00B5: Micro Sign +// U+00B6: Pilcrow Sign +// U+00B7: Middle Dot +// U+00B8: Cedilla +// U+00B9: Superscript One + -1 * 14 12 03 00 06 B4 00 01 06 B4 00 02 06 B4 00 + -1 sprites/chars.png 8bpp 150 130 4 12 0 -1 normal + -1 sprites/chars.png 8bpp 160 130 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 180 130 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 200 130 3 12 0 -1 normal + -1 sprites/chars.png 8bpp 210 130 4 12 0 -1 normal + -1 sprites/chars.png 8bpp 220 130 5 12 0 -1 normal + -1 sprites/chars.png 8bpp 150 150 2 7 0 0 normal + -1 sprites/chars.png 8bpp 160 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 180 150 6 7 0 0 normal + -1 sprites/chars.png 8bpp 200 150 1 7 0 0 normal + -1 sprites/chars.png 8bpp 210 150 2 7 0 0 normal + -1 sprites/chars.png 8bpp 220 150 2 7 0 0 normal + -1 sprites/chars.png 8bpp 150 160 4 21 0 -2 normal + -1 sprites/chars.png 8bpp 160 160 15 21 0 -2 normal + -1 sprites/chars.png 8bpp 180 160 13 21 0 -2 normal + -1 sprites/chars.png 8bpp 200 160 3 21 0 -2 normal + -1 sprites/chars.png 8bpp 210 160 5 21 0 -2 normal + -1 sprites/chars.png 8bpp 220 160 6 21 0 -2 normal + +// U+00BC: Vulgar Fraction One Quarter +// U+00BD: Vulgar Fraction One Half + -1 * 14 12 03 00 02 BC 00 01 02 BC 00 02 02 BC 00 + -1 sprites/chars.png 8bpp 230 130 10 12 0 -1 normal + -1 sprites/chars.png 8bpp 250 130 10 12 0 -1 normal + -1 sprites/chars.png 8bpp 230 150 9 7 0 0 normal + -1 sprites/chars.png 8bpp 250 150 9 7 0 0 normal + -1 sprites/chars.png 8bpp 230 160 16 21 0 -2 normal + -1 sprites/chars.png 8bpp 250 160 16 21 0 -2 normal + +// New characters, all fonts + +// U+0100 ... U+017F: Latin Extended-A + -1 * 34 12 08 00 78 00 01 00 07 79 01 01 78 00 01 01 07 79 01 02 78 00 01 02 07 79 01 03 78 00 01 03 07 79 01 + -1 sprites/chars.png 8bpp 270 130 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 300 130 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 320 130 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 350 130 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 370 130 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 400 130 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 420 130 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 440 130 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 460 130 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 480 130 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 500 130 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 520 130 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 540 130 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 560 130 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 580 130 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 600 130 9 12 0 -1 normal + -1 sprites/chars.png 8bpp 620 130 9 12 0 -1 normal + -1 sprites/chars.png 8bpp 640 130 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 660 130 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 680 130 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 700 130 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 720 130 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 740 130 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 760 130 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 10 190 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 30 190 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 50 190 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 70 190 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 90 190 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 110 190 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 130 190 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 150 190 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 170 190 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 190 190 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 210 190 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 230 190 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 250 190 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 270 190 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 290 190 10 12 0 -1 normal + -1 sprites/chars.png 8bpp 310 190 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 330 190 5 12 0 -1 normal + -1 sprites/chars.png 8bpp 340 190 5 12 0 -1 normal + -1 sprites/chars.png 8bpp 350 190 5 12 0 -1 normal + -1 sprites/chars.png 8bpp 360 190 5 12 0 -1 normal + -1 sprites/chars.png 8bpp 370 190 5 12 0 -1 normal + -1 sprites/chars.png 8bpp 380 190 5 12 0 -1 normal + -1 sprites/chars.png 8bpp 390 190 3 12 0 -1 normal + -1 sprites/chars.png 8bpp 400 190 3 12 0 -1 normal + -1 sprites/chars.png 8bpp 410 190 3 12 0 -1 normal + -1 sprites/chars.png 8bpp 420 190 3 12 0 -1 normal + -1 sprites/chars.png 8bpp 430 190 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 460 190 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 480 190 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 500 190 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 520 190 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 540 190 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 560 190 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 580 190 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 600 190 4 12 0 -1 normal + -1 sprites/chars.png 8bpp 610 190 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 630 190 3 12 0 -1 normal + -1 sprites/chars.png 8bpp 640 190 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 660 190 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 670 190 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 690 190 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 710 190 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 730 190 5 12 0 -1 normal + -1 sprites/chars.png 8bpp 740 190 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 760 190 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 10 250 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 30 250 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 50 250 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 70 250 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 90 250 9 12 0 -1 normal + -1 sprites/chars.png 8bpp 110 250 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 130 250 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 150 250 9 12 0 -1 normal + -1 sprites/chars.png 8bpp 170 250 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 190 250 9 12 0 -1 normal + -1 sprites/chars.png 8bpp 210 250 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 230 250 9 12 0 -1 normal + -1 sprites/chars.png 8bpp 250 250 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 270 250 13 12 0 -1 normal + -1 sprites/chars.png 8bpp 300 250 9 12 0 -1 normal + -1 sprites/chars.png 8bpp 320 250 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 340 250 5 12 0 -1 normal + -1 sprites/chars.png 8bpp 360 250 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 380 250 5 12 0 -1 normal + -1 sprites/chars.png 8bpp 400 250 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 420 250 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 440 250 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 460 250 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 480 250 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 500 250 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 520 250 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 540 250 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 560 250 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 580 250 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 600 250 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 620 250 5 12 0 -1 normal + -1 sprites/chars.png 8bpp 630 250 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 650 250 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 670 250 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 690 250 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 700 250 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 720 250 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 740 250 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 760 250 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 10 310 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 30 310 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 50 310 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 70 310 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 90 310 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 110 310 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 130 310 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 150 310 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 170 310 12 12 0 -1 normal + -1 sprites/chars.png 8bpp 200 310 10 12 0 -1 normal + -1 sprites/chars.png 8bpp 230 310 9 12 0 -1 normal + -1 sprites/chars.png 8bpp 250 310 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 270 310 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 290 310 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 310 310 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 330 310 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 350 310 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 370 310 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 390 310 5 12 0 -1 normal + -1 sprites/chars.png 8bpp 270 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 300 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 320 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 350 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 370 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 400 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 420 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 440 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 460 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 480 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 500 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 520 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 540 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 560 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 580 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 600 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 620 150 5 7 0 0 normal + -1 sprites/chars.png 8bpp 640 150 5 7 0 0 normal + -1 sprites/chars.png 8bpp 660 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 680 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 700 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 720 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 740 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 760 150 3 7 0 0 normal + -1 sprites/chars.png 8bpp 10 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 30 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 50 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 70 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 90 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 110 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 130 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 150 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 170 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 190 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 210 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 230 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 250 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 270 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 290 210 5 7 0 0 normal + -1 sprites/chars.png 8bpp 310 210 5 7 0 0 normal + -1 sprites/chars.png 8bpp 330 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 340 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 350 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 360 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 370 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 380 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 390 210 2 7 0 0 normal + -1 sprites/chars.png 8bpp 400 210 2 7 0 0 normal + -1 sprites/chars.png 8bpp 410 210 1 7 0 0 normal + -1 sprites/chars.png 8bpp 420 210 1 7 0 0 normal + -1 sprites/chars.png 8bpp 430 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 460 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 480 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 500 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 520 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 540 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 560 210 5 7 0 0 normal + -1 sprites/chars.png 8bpp 580 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 600 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 610 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 630 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 640 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 660 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 670 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 690 210 3 7 0 0 normal + -1 sprites/chars.png 8bpp 710 210 4 7 0 0 normal + -1 sprites/chars.png 8bpp 730 210 4 7 0 0 normal + -1 sprites/chars.png 8bpp 740 210 4 7 0 0 normal + -1 sprites/chars.png 8bpp 760 210 4 7 0 0 normal + -1 sprites/chars.png 8bpp 10 270 4 7 0 0 normal + -1 sprites/chars.png 8bpp 30 270 4 7 0 0 normal + -1 sprites/chars.png 8bpp 50 270 4 7 0 0 normal + -1 sprites/chars.png 8bpp 70 270 4 7 0 0 normal + -1 sprites/chars.png 8bpp 90 270 6 7 0 0 normal + -1 sprites/chars.png 8bpp 110 270 4 7 0 0 normal + -1 sprites/chars.png 8bpp 130 270 4 7 0 0 normal + -1 sprites/chars.png 8bpp 150 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 170 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 190 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 210 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 230 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 250 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 270 270 4 7 0 0 normal + -1 sprites/chars.png 8bpp 300 270 4 7 0 0 normal + -1 sprites/chars.png 8bpp 320 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 340 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 360 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 380 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 400 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 420 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 440 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 460 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 480 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 500 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 520 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 540 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 560 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 580 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 600 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 620 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 630 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 650 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 670 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 690 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 700 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 720 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 740 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 760 270 3 7 0 0 normal + -1 sprites/chars.png 8bpp 10 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 30 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 50 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 70 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 90 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 110 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 130 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 150 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 170 330 5 7 0 0 normal + -1 sprites/chars.png 8bpp 200 330 5 7 0 0 normal + -1 sprites/chars.png 8bpp 230 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 250 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 270 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 290 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 310 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 330 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 350 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 370 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 390 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 270 160 20 21 0 -2 normal + -1 sprites/chars.png 8bpp 300 160 13 21 0 -2 normal + -1 sprites/chars.png 8bpp 320 160 20 21 0 -2 normal + -1 sprites/chars.png 8bpp 350 160 13 21 0 -2 normal + -1 sprites/chars.png 8bpp 370 160 20 21 0 -2 normal + -1 sprites/chars.png 8bpp 400 160 13 21 0 -2 normal + -1 sprites/chars.png 8bpp 420 160 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 440 160 11 21 0 -2 normal + -1 sprites/chars.png 8bpp 460 160 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 480 160 11 21 0 -2 normal + -1 sprites/chars.png 8bpp 500 160 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 520 160 11 21 0 -2 normal + -1 sprites/chars.png 8bpp 540 160 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 560 160 11 21 0 -2 normal + -1 sprites/chars.png 8bpp 580 160 17 21 0 -2 normal + -1 sprites/chars.png 8bpp 600 160 16 21 0 -2 normal + -1 sprites/chars.png 8bpp 620 160 17 21 0 -2 normal + -1 sprites/chars.png 8bpp 640 160 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 660 160 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 680 160 12 21 0 -2 normal + -1 sprites/chars.png 8bpp 700 160 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 720 160 12 21 0 -2 normal + -1 sprites/chars.png 8bpp 740 160 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 760 160 12 21 0 -2 normal + -1 sprites/chars.png 8bpp 10 220 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 30 220 12 21 0 -2 normal + -1 sprites/chars.png 8bpp 50 220 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 70 220 12 21 0 -2 normal + -1 sprites/chars.png 8bpp 90 220 18 21 0 -2 normal + -1 sprites/chars.png 8bpp 110 220 13 21 0 -2 normal + -1 sprites/chars.png 8bpp 130 220 18 21 0 -2 normal + -1 sprites/chars.png 8bpp 150 220 13 21 0 -2 normal + -1 sprites/chars.png 8bpp 170 220 18 21 0 -2 normal + -1 sprites/chars.png 8bpp 190 220 13 21 0 -2 normal + -1 sprites/chars.png 8bpp 210 220 18 21 0 -2 normal + -1 sprites/chars.png 8bpp 230 220 13 21 0 -2 normal + -1 sprites/chars.png 8bpp 250 220 17 21 0 -2 normal + -1 sprites/chars.png 8bpp 270 220 15 21 0 -2 normal + -1 sprites/chars.png 8bpp 290 220 17 21 0 -2 normal + -1 sprites/chars.png 8bpp 310 220 15 21 0 -2 normal + -1 sprites/chars.png 8bpp 330 220 9 21 0 -2 normal + -1 sprites/chars.png 8bpp 340 220 7 21 0 -2 normal + -1 sprites/chars.png 8bpp 350 220 9 21 0 -2 normal + -1 sprites/chars.png 8bpp 360 220 7 21 0 -2 normal + -1 sprites/chars.png 8bpp 370 220 9 21 0 -2 normal + -1 sprites/chars.png 8bpp 380 220 7 21 0 -2 normal + -1 sprites/chars.png 8bpp 390 220 9 21 0 -2 normal + -1 sprites/chars.png 8bpp 400 220 7 21 0 -2 normal + -1 sprites/chars.png 8bpp 410 220 9 21 0 -2 normal + -1 sprites/chars.png 8bpp 420 220 7 21 0 -2 normal + -1 sprites/chars.png 8bpp 430 220 19 21 0 -2 normal + -1 sprites/chars.png 8bpp 460 220 13 21 0 -2 normal + -1 sprites/chars.png 8bpp 480 220 13 21 0 -2 normal + -1 sprites/chars.png 8bpp 500 220 10 21 0 -2 normal + -1 sprites/chars.png 8bpp 520 220 18 21 0 -2 normal + -1 sprites/chars.png 8bpp 540 220 15 21 0 -2 normal + -1 sprites/chars.png 8bpp 560 220 15 21 0 -2 normal + -1 sprites/chars.png 8bpp 580 220 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 600 220 7 21 0 -2 normal + -1 sprites/chars.png 8bpp 610 220 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 630 220 7 21 0 -2 normal + -1 sprites/chars.png 8bpp 640 220 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 660 220 9 21 0 -2 normal + -1 sprites/chars.png 8bpp 670 220 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 690 220 10 21 0 -2 normal + -1 sprites/chars.png 8bpp 710 220 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 730 220 7 21 0 -2 normal + -1 sprites/chars.png 8bpp 740 220 18 21 0 -2 normal + -1 sprites/chars.png 8bpp 760 220 15 21 0 -2 normal + -1 sprites/chars.png 8bpp 10 280 18 21 0 -2 normal + -1 sprites/chars.png 8bpp 30 280 15 21 0 -2 normal + -1 sprites/chars.png 8bpp 50 280 18 21 0 -2 normal + -1 sprites/chars.png 8bpp 70 280 15 21 0 -2 normal + -1 sprites/chars.png 8bpp 90 280 19 21 0 -2 normal + -1 sprites/chars.png 8bpp 110 280 18 21 0 -2 normal + -1 sprites/chars.png 8bpp 130 280 13 21 0 -2 normal + -1 sprites/chars.png 8bpp 150 280 15 21 0 -2 normal + -1 sprites/chars.png 8bpp 170 280 11 21 0 -2 normal + -1 sprites/chars.png 8bpp 190 280 15 21 0 -2 normal + -1 sprites/chars.png 8bpp 210 280 11 21 0 -2 normal + -1 sprites/chars.png 8bpp 230 280 15 21 0 -2 normal + -1 sprites/chars.png 8bpp 250 280 11 21 0 -2 normal + -1 sprites/chars.png 8bpp 270 280 23 21 0 -2 normal + -1 sprites/chars.png 8bpp 300 280 19 21 0 -2 normal + -1 sprites/chars.png 8bpp 320 280 16 21 0 -2 normal + -1 sprites/chars.png 8bpp 340 280 11 21 0 -2 normal + -1 sprites/chars.png 8bpp 360 280 16 21 0 -2 normal + -1 sprites/chars.png 8bpp 380 280 11 21 0 -2 normal + -1 sprites/chars.png 8bpp 400 280 16 21 0 -2 normal + -1 sprites/chars.png 8bpp 420 280 11 21 0 -2 normal + -1 sprites/chars.png 8bpp 440 280 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 460 280 10 21 0 -2 normal + -1 sprites/chars.png 8bpp 480 280 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 500 280 10 21 0 -2 normal + -1 sprites/chars.png 8bpp 520 280 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 540 280 10 21 0 -2 normal + -1 sprites/chars.png 8bpp 560 280 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 580 280 10 21 0 -2 normal + -1 sprites/chars.png 8bpp 600 280 13 21 0 -2 normal + -1 sprites/chars.png 8bpp 620 280 8 21 0 -2 normal + -1 sprites/chars.png 8bpp 630 280 13 21 0 -2 normal + -1 sprites/chars.png 8bpp 650 280 12 21 0 -2 normal + -1 sprites/chars.png 8bpp 670 280 13 21 0 -2 normal + -1 sprites/chars.png 8bpp 690 280 8 21 0 -2 normal + -1 sprites/chars.png 8bpp 700 280 17 21 0 -2 normal + -1 sprites/chars.png 8bpp 720 280 15 21 0 -2 normal + -1 sprites/chars.png 8bpp 740 280 17 21 0 -2 normal + -1 sprites/chars.png 8bpp 760 280 15 21 0 -2 normal + -1 sprites/chars.png 8bpp 10 340 17 21 0 -2 normal + -1 sprites/chars.png 8bpp 30 340 15 21 0 -2 normal + -1 sprites/chars.png 8bpp 50 340 17 21 0 -2 normal + -1 sprites/chars.png 8bpp 70 340 15 21 0 -2 normal + -1 sprites/chars.png 8bpp 90 340 17 21 0 -2 normal + -1 sprites/chars.png 8bpp 110 340 15 21 0 -2 normal + -1 sprites/chars.png 8bpp 130 340 17 21 0 -2 normal + -1 sprites/chars.png 8bpp 150 340 15 21 0 -2 normal + -1 sprites/chars.png 8bpp 170 340 24 21 0 -2 normal + -1 sprites/chars.png 8bpp 200 340 22 21 0 -2 normal + -1 sprites/chars.png 8bpp 230 340 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 250 340 16 21 0 -2 normal + -1 sprites/chars.png 8bpp 270 340 13 21 0 -2 normal + -1 sprites/chars.png 8bpp 290 340 12 21 0 -2 normal + -1 sprites/chars.png 8bpp 310 340 13 21 0 -2 normal + -1 sprites/chars.png 8bpp 330 340 12 21 0 -2 normal + -1 sprites/chars.png 8bpp 350 340 13 21 0 -2 normal + -1 sprites/chars.png 8bpp 370 340 12 21 0 -2 normal + -1 sprites/chars.png 8bpp 390 340 10 21 0 -2 normal + -1 sprites/mono.png 8bpp 10 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 25 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 40 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 55 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 70 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 85 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 100 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 115 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 130 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 145 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 160 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 175 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 190 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 205 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 220 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 235 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 250 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 265 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 280 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 295 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 310 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 325 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 340 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 355 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 370 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 385 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 400 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 415 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 430 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 445 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 460 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 475 170 7 13 0 0 normal + -1 sprites/mono.png 8bpp 10 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 25 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 40 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 55 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 70 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 85 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 100 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 115 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 130 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 145 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 160 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 175 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 190 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 205 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 220 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 235 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 250 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 265 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 280 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 295 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 310 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 325 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 340 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 355 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 370 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 385 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 400 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 415 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 430 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 445 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 460 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 475 190 7 13 0 0 normal + -1 sprites/mono.png 8bpp 10 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 25 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 40 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 55 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 70 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 85 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 100 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 115 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 130 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 145 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 160 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 175 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 190 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 205 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 220 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 235 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 250 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 265 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 280 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 295 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 310 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 325 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 340 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 355 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 370 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 385 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 400 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 415 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 430 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 445 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 460 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 475 210 7 13 0 0 normal + -1 sprites/mono.png 8bpp 10 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 25 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 40 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 55 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 70 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 85 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 100 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 115 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 130 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 145 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 160 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 175 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 190 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 205 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 220 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 235 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 250 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 265 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 280 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 295 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 310 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 325 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 340 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 355 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 385 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 400 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 415 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 430 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 445 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 460 230 7 13 0 0 normal + -1 sprites/mono.png 8bpp 475 230 7 13 0 0 normal + +// U+018F: Latin Capital Letter Schwa + -1 * 18 12 04 00 01 8F 01 01 01 8F 01 02 01 8F 01 03 01 8F 01 + -1 sprites/chars.png 8bpp 410 310 9 12 0 -1 normal + -1 sprites/chars.png 8bpp 410 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 410 340 16 21 0 -2 normal + -1 sprites/mono.png 8bpp 10 250 7 13 0 0 normal + +// U+0192: Latin Small Letter F With Hook + -1 * 18 12 04 00 01 92 01 01 01 92 01 02 01 92 01 03 01 92 01 + -1 sprites/chars.png 8bpp 430 310 9 12 0 -1 normal + -1 sprites/chars.png 8bpp 430 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 430 340 14 21 0 -2 normal + -1 sprites/mono.png 8bpp 25 250 7 13 0 0 normal + +// U+01B5: Latin Capital Letter Z With Stroke +// U+01B6: Latin Small Letter Z With Stroke + -1 * 18 12 04 00 02 B5 01 01 02 B5 01 02 02 B5 01 03 02 B5 01 + -1 sprites/chars.png 8bpp 450 310 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 470 310 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 450 330 4 7 0 0 normal + -1 sprites/chars.png 8bpp 470 330 4 7 0 0 normal + -1 sprites/chars.png 8bpp 450 340 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 470 340 12 21 0 -2 normal + -1 sprites/mono.png 8bpp 40 250 7 13 0 0 normal + -1 sprites/mono.png 8bpp 55 250 7 13 0 0 normal + +// U+0218: Latin Capital Letter S With Comma Below +// U+0219: Latin Small Letter S With Comma Below +// U+021A: Latin Capital Letter T With Comma Below +// U+021B: Latin Small Letter T With Comma Below + -1 * 18 12 04 00 04 18 02 01 04 18 02 02 04 18 02 03 04 18 02 + -1 sprites/chars.png 8bpp 490 310 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 510 310 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 530 310 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 550 310 5 12 0 -1 normal + -1 sprites/chars.png 8bpp 490 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 510 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 530 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 550 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 490 340 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 510 340 10 21 0 -2 normal + -1 sprites/chars.png 8bpp 530 340 13 21 0 -2 normal + -1 sprites/chars.png 8bpp 550 340 8 21 0 -2 normal + -1 sprites/mono.png 8bpp 70 250 7 13 0 0 normal + -1 sprites/mono.png 8bpp 85 250 7 13 0 0 normal + -1 sprites/mono.png 8bpp 100 250 7 13 0 0 normal + -1 sprites/mono.png 8bpp 115 250 7 13 0 0 normal + +// U+0259: Latin Small Letter Schwa + -1 * 18 12 04 00 01 59 02 01 01 59 02 02 01 59 02 03 01 59 02 + -1 sprites/chars.png 8bpp 560 310 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 560 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 560 340 12 21 0 -2 normal + -1 sprites/mono.png 8bpp 130 250 7 13 0 0 normal + +// U+02BB: Modifier Letter Turned Comma + -1 * 18 12 04 00 01 BB 02 01 01 BB 02 02 01 BB 02 03 01 BB 02 + -1 sprites/chars.png 8bpp 580 310 3 12 0 -1 normal + -1 sprites/chars.png 8bpp 580 330 1 7 0 0 normal + -1 sprites/chars.png 8bpp 580 340 4 21 0 -2 normal + -1 sprites/mono.png 8bpp 145 250 7 13 0 0 normal + +// U+02C7: Caron + -1 * 18 12 04 00 01 C7 02 01 01 C7 02 02 01 C7 02 03 01 C7 02 + -1 sprites/chars.png 8bpp 430 370 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 430 390 3 7 0 0 normal + -1 sprites/chars.png 8bpp 430 400 7 21 0 -2 normal + -1 sprites/mono.png 8bpp 130 270 7 13 0 0 normal + +// U+058F: Armenian Dram Sign + -1 * 18 12 04 00 01 8F 05 01 01 8F 05 02 01 8F 05 03 01 8F 05 + -1 sprites/chars.png 8bpp 590 310 9 12 0 -1 normal + -1 sprites/chars.png 8bpp 590 330 4 7 0 0 normal + -1 sprites/chars.png 8bpp 590 340 18 21 0 -2 normal + -1 sprites/mono.png 8bpp 160 250 7 13 0 0 normal + +// U+0E3F: Thai Currency Symbol Baht + -1 * 18 12 04 00 01 3F 0E 01 01 3F 0E 02 01 3F 0E 03 01 3F 0E + -1 sprites/chars.png 8bpp 610 310 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 610 330 5 7 0 0 normal + -1 sprites/chars.png 8bpp 610 340 15 21 0 -2 normal + -1 sprites/mono.png 8bpp 175 250 7 13 0 0 normal + +// U+2010: Hyphen + -1 * 18 12 04 00 01 10 20 01 01 10 20 02 01 10 20 03 01 10 20 + -1 sprites/chars.png 8bpp 480 370 4 12 0 -1 normal + -1 sprites/chars.png 8bpp 480 390 2 7 0 0 normal + -1 sprites/chars.png 8bpp 480 400 6 21 0 -2 normal + -1 sprites/mono.png 8bpp 160 270 7 13 0 0 normal + +// U+2013: En Dash +// U+2014: Em Dash +// U+2015: Horizontal Bar + -1 * 18 12 04 00 03 13 20 01 03 13 20 02 03 13 20 03 03 13 20 + -1 sprites/chars.png 8bpp 630 310 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 450 370 12 12 0 -1 normal + -1 sprites/chars.png 8bpp 490 370 10 12 0 -1 normal + -1 sprites/chars.png 8bpp 630 330 4 7 0 0 normal + -1 sprites/chars.png 8bpp 450 390 6 7 0 0 normal + -1 sprites/chars.png 8bpp 490 390 5 7 0 0 normal + -1 sprites/chars.png 8bpp 630 340 15 21 0 -2 normal + -1 sprites/chars.png 8bpp 450 400 21 21 0 -2 normal + -1 sprites/chars.png 8bpp 490 400 18 21 0 -2 normal + -1 sprites/mono.png 8bpp 190 250 7 13 0 0 normal + -1 sprites/mono.png 8bpp 145 270 7 13 0 0 normal + -1 sprites/mono.png 8bpp 175 270 7 13 0 0 normal + +// U+2018: Left Single Quotation Mark +// U+2019: Right Single Quotation Mark +// U+201A: Single Low-9 Quotation Mark +// U+201B: Single High-Reversed-9 Quotation Mark +// U+201C: Left Double Quotation Mark +// U+201D: Right Double Quotation Mark +// U+201E: Double Low-9 Quotation Mark +// U+201F: Double High-Reversed-9 Quotation Mark + -1 * 18 12 04 00 08 18 20 01 08 18 20 02 08 18 20 03 08 18 20 + -1 sprites/chars.png 8bpp 510 370 4 12 0 -1 normal + -1 sprites/chars.png 8bpp 650 310 4 12 0 -1 normal + -1 sprites/chars.png 8bpp 520 370 4 12 0 -1 normal + -1 sprites/chars.png 8bpp 530 370 4 12 0 -1 normal + -1 sprites/chars.png 8bpp 660 310 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 540 370 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 670 310 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 550 370 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 510 390 1 7 0 0 normal + -1 sprites/chars.png 8bpp 650 330 1 7 0 0 normal + -1 sprites/chars.png 8bpp 520 390 1 7 0 0 normal + -1 sprites/chars.png 8bpp 530 390 1 7 0 0 normal + -1 sprites/chars.png 8bpp 660 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 540 390 3 7 0 0 normal + -1 sprites/chars.png 8bpp 670 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 550 390 3 7 0 0 normal + -1 sprites/chars.png 8bpp 510 400 3 21 0 -2 normal + -1 sprites/chars.png 8bpp 650 340 3 21 0 -2 normal + -1 sprites/chars.png 8bpp 520 400 3 21 0 -2 normal + -1 sprites/chars.png 8bpp 530 400 3 21 0 -2 normal + -1 sprites/chars.png 8bpp 660 340 9 21 0 -2 normal + -1 sprites/chars.png 8bpp 540 400 9 21 0 -2 normal + -1 sprites/chars.png 8bpp 670 340 9 21 0 -2 normal + -1 sprites/chars.png 8bpp 550 400 9 21 0 -2 normal + -1 sprites/mono.png 8bpp 190 270 7 13 0 0 normal + -1 sprites/mono.png 8bpp 205 250 7 13 0 0 normal + -1 sprites/mono.png 8bpp 205 270 7 13 0 0 normal + -1 sprites/mono.png 8bpp 220 270 7 13 0 0 normal + -1 sprites/mono.png 8bpp 220 250 7 13 0 0 normal + -1 sprites/mono.png 8bpp 235 270 7 13 0 0 normal + -1 sprites/mono.png 8bpp 235 250 7 13 0 0 normal + -1 sprites/mono.png 8bpp 250 270 7 13 0 0 normal + +// U+2026: Horizontal Ellipsis + -1 * 18 12 04 00 01 26 20 01 01 26 20 02 01 26 20 03 01 26 20 + -1 sprites/chars.png 8bpp 560 370 11 12 0 -1 normal + -1 sprites/chars.png 8bpp 560 390 5 7 0 0 normal + -1 sprites/chars.png 8bpp 560 400 15 21 0 -2 normal + -1 sprites/mono.png 8bpp 265 270 7 13 0 0 normal + +// U+2039: Single Left-Pointing Angle Quotation Mark +// U+203A: Single Right-Pointing Angle Quotation Mark + -1 * 18 12 04 00 02 39 20 01 02 39 20 02 02 39 20 03 02 39 20 + -1 sprites/chars.png 8bpp 580 370 5 12 0 -1 normal + -1 sprites/chars.png 8bpp 680 310 5 12 0 -1 normal + -1 sprites/chars.png 8bpp 580 390 2 7 0 0 normal + -1 sprites/chars.png 8bpp 680 330 2 7 0 0 normal + -1 sprites/chars.png 8bpp 580 400 7 21 0 -2 normal + -1 sprites/chars.png 8bpp 680 340 7 21 0 -2 normal + -1 sprites/mono.png 8bpp 280 270 7 13 0 0 normal + -1 sprites/mono.png 8bpp 250 250 7 13 0 0 normal + +// U+20A1: Colon Sign +// U+20A2: Cruzeiro Sign +// U+20A3: French Franc Sign +// U+20A4: Lira Sign + -1 * 18 12 04 00 04 A1 20 01 04 A1 20 02 04 A1 20 03 04 A1 20 + -1 sprites/chars.png 8bpp 690 310 9 12 0 -1 normal + -1 sprites/chars.png 8bpp 710 310 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 730 310 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 750 310 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 690 330 4 7 0 0 normal + -1 sprites/chars.png 8bpp 710 330 4 7 0 0 normal + -1 sprites/chars.png 8bpp 730 330 4 7 0 0 normal + -1 sprites/chars.png 8bpp 750 330 3 7 0 0 normal + -1 sprites/chars.png 8bpp 690 340 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 710 340 16 21 0 -2 normal + -1 sprites/chars.png 8bpp 730 340 13 21 0 -2 normal + -1 sprites/chars.png 8bpp 750 340 11 21 0 -2 normal + -1 sprites/mono.png 8bpp 265 250 7 13 0 0 normal + -1 sprites/mono.png 8bpp 280 250 7 13 0 0 normal + -1 sprites/mono.png 8bpp 295 250 7 13 0 0 normal + -1 sprites/mono.png 8bpp 310 250 7 13 0 0 normal + +// U+20A6: Naira Sign + -1 * 18 12 04 00 01 A6 20 01 01 A6 20 02 01 A6 20 03 01 A6 20 + -1 sprites/chars.png 8bpp 770 310 10 12 0 -1 normal + -1 sprites/chars.png 8bpp 770 330 6 7 0 0 normal + -1 sprites/chars.png 8bpp 770 340 18 21 0 -2 normal + -1 sprites/mono.png 8bpp 325 250 7 13 0 0 normal + +// U+20A8: Rupee Sign +// U+20A9: Won Sign +// U+20AA: New Shequel Sign +// U+20AB: Dong Sign +// U+20AC: Euro Sign +// U+20AD: Kip Sign +// U+20AE: Tugrik Sign +// U+20AF: Drachma Sign + -1 * 18 12 04 00 08 A8 20 01 08 A8 20 02 08 A8 20 03 08 A8 20 + -1 sprites/chars.png 8bpp 10 370 12 12 0 -1 normal + -1 sprites/chars.png 8bpp 40 370 13 12 0 -1 normal + -1 sprites/chars.png 8bpp 70 370 12 12 0 -1 normal + -1 sprites/chars.png 8bpp 90 370 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 110 370 9 12 0 -1 normal + -1 sprites/chars.png 8bpp 130 370 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 150 370 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 170 370 14 12 0 -1 normal + -1 sprites/chars.png 8bpp 10 390 6 7 0 0 normal + -1 sprites/chars.png 8bpp 40 390 7 7 0 0 normal + -1 sprites/chars.png 8bpp 70 390 7 7 0 0 normal + -1 sprites/chars.png 8bpp 90 390 4 7 0 0 normal + -1 sprites/chars.png 8bpp 110 390 4 7 0 0 normal + -1 sprites/chars.png 8bpp 130 390 4 7 0 0 normal + -1 sprites/chars.png 8bpp 150 390 3 7 0 0 normal + -1 sprites/chars.png 8bpp 170 390 6 7 0 0 normal + -1 sprites/chars.png 8bpp 10 400 22 21 0 -2 normal + -1 sprites/chars.png 8bpp 40 400 24 21 0 -2 normal + -1 sprites/chars.png 8bpp 70 400 17 21 0 -2 normal + -1 sprites/chars.png 8bpp 90 400 13 21 0 -2 normal + -1 sprites/chars.png 8bpp 110 400 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 130 400 18 21 0 -2 normal + -1 sprites/chars.png 8bpp 150 400 13 21 0 -2 normal + -1 sprites/chars.png 8bpp 170 400 28 21 0 -2 normal + -1 sprites/mono.png 8bpp 340 250 7 13 0 0 normal + -1 sprites/mono.png 8bpp 355 250 7 13 0 0 normal + -1 sprites/mono.png 8bpp 370 250 7 13 0 0 normal + -1 sprites/mono.png 8bpp 385 250 7 13 0 0 normal + -1 sprites/mono.png 8bpp 400 250 7 13 0 0 normal + -1 sprites/mono.png 8bpp 415 250 7 13 0 0 normal + -1 sprites/mono.png 8bpp 430 250 7 13 0 0 normal + -1 sprites/mono.png 8bpp 445 250 7 13 0 0 normal + +// U+20B1: Peso Sign +// U+20B2: Guarani Sign +// U+20B3: Austral Sign +// U+20B4: Hryvnia Sign +// U+20B5: Cedi Sign + -1 * 18 12 04 00 05 B1 20 01 05 B1 20 02 05 B1 20 03 05 B1 20 + -1 sprites/chars.png 8bpp 200 370 9 12 0 -1 normal + -1 sprites/chars.png 8bpp 220 370 9 12 0 -1 normal + -1 sprites/chars.png 8bpp 240 370 10 12 0 -1 normal + -1 sprites/chars.png 8bpp 270 370 9 12 0 -1 normal + -1 sprites/chars.png 8bpp 290 370 9 12 0 -1 normal + -1 sprites/chars.png 8bpp 200 390 5 7 0 0 normal + -1 sprites/chars.png 8bpp 220 390 5 7 0 0 normal + -1 sprites/chars.png 8bpp 240 390 5 7 0 0 normal + -1 sprites/chars.png 8bpp 270 390 5 7 0 0 normal + -1 sprites/chars.png 8bpp 290 390 4 7 0 0 normal + -1 sprites/chars.png 8bpp 200 400 15 21 0 -2 normal + -1 sprites/chars.png 8bpp 220 400 18 21 0 -2 normal + -1 sprites/chars.png 8bpp 240 400 20 21 0 -2 normal + -1 sprites/chars.png 8bpp 270 400 14 21 0 -2 normal + -1 sprites/chars.png 8bpp 290 400 14 21 0 -2 normal + -1 sprites/mono.png 8bpp 460 250 7 13 0 0 normal + -1 sprites/mono.png 8bpp 475 250 7 13 0 0 normal + -1 sprites/mono.png 8bpp 10 270 7 13 0 0 normal + -1 sprites/mono.png 8bpp 25 270 7 13 0 0 normal + -1 sprites/mono.png 8bpp 40 270 7 13 0 0 normal + +// U+20B7: Spesmilo Sign +// U+20B8: Tenge Sign +// U+20B9: Indian Rupee Sign + -1 * 18 12 04 00 03 B7 20 01 03 B7 20 02 03 B7 20 03 03 B7 20 + -1 sprites/chars.png 8bpp 310 370 10 12 0 -1 normal + -1 sprites/chars.png 8bpp 330 370 7 12 0 -1 normal + -1 sprites/chars.png 8bpp 350 370 8 12 0 -1 normal + -1 sprites/chars.png 8bpp 310 390 6 7 0 0 normal + -1 sprites/chars.png 8bpp 330 390 3 7 0 0 normal + -1 sprites/chars.png 8bpp 350 390 4 7 0 0 normal + -1 sprites/chars.png 8bpp 310 400 17 21 0 -2 normal + -1 sprites/chars.png 8bpp 330 400 13 21 0 -2 normal + -1 sprites/chars.png 8bpp 350 400 14 21 0 -2 normal + -1 sprites/mono.png 8bpp 55 270 7 13 0 0 normal + -1 sprites/mono.png 8bpp 70 270 7 13 0 0 normal + -1 sprites/mono.png 8bpp 85 270 7 13 0 0 normal + +// U+2116: Numero Sign +// U+2117: Sound Recording Copyright + -1 * 18 12 04 00 02 16 21 01 02 16 21 02 02 16 21 03 02 16 21 + -1 sprites/chars.png 8bpp 370 370 14 12 0 -1 normal + -1 sprites/chars.png 8bpp 590 370 13 12 0 -1 normal + -1 sprites/chars.png 8bpp 370 390 8 7 0 0 normal + -1 sprites/chars.png 8bpp 590 390 6 7 0 0 normal + -1 sprites/chars.png 8bpp 370 400 27 21 0 -2 normal + -1 sprites/chars.png 8bpp 590 400 16 21 0 -2 normal + -1 sprites/mono.png 8bpp 100 270 7 13 0 0 normal + -1 sprites/mono.png 8bpp 295 270 7 13 0 0 normal + +// U+2122: Trade Mark Sign + -1 * 18 12 04 00 01 22 21 01 01 22 21 02 01 22 21 03 01 22 21 + -1 sprites/chars.png 8bpp 400 370 13 12 0 -1 normal + -1 sprites/chars.png 8bpp 400 390 9 7 0 0 normal + -1 sprites/chars.png 8bpp 400 400 20 21 0 -2 normal + -1 sprites/mono.png 8bpp 115 270 7 13 0 0 normal + +// U+2212: Minus Sign + -1 * 18 12 04 00 01 12 22 01 01 12 22 02 01 12 22 03 01 12 22 + -1 sprites/chars.png 8bpp 610 370 6 12 0 -1 normal + -1 sprites/chars.png 8bpp 610 390 3 7 0 0 normal + -1 sprites/chars.png 8bpp 610 400 9 21 0 -2 normal + -1 sprites/mono.png 8bpp 310 270 7 13 0 0 normal + +// U+27E8: Mathematical Left Angle Bracket +// U+27E9: Mathematical Right Angle Bracket + -1 * 18 12 04 00 02 E8 27 01 02 E8 27 02 02 E8 27 03 02 E8 27 + -1 sprites/chars.png 8bpp 620 370 5 12 0 -1 normal + -1 sprites/chars.png 8bpp 630 370 5 12 0 -1 normal + -1 sprites/chars.png 8bpp 620 390 3 7 0 0 normal + -1 sprites/chars.png 8bpp 630 390 3 7 0 0 normal + -1 sprites/chars.png 8bpp 620 400 6 21 0 -2 normal + -1 sprites/chars.png 8bpp 630 400 6 21 0 -2 normal + -1 sprites/mono.png 8bpp 325 270 7 13 0 0 normal + -1 sprites/mono.png 8bpp 340 270 7 13 0 0 normal diff --git a/media/extra_grf/chars.png b/media/extra_grf/chars.png new file mode 100644 index 0000000..34a4a67 Binary files /dev/null and b/media/extra_grf/chars.png differ diff --git a/media/extra_grf/elrails.nfo b/media/extra_grf/elrails.nfo new file mode 100644 index 0000000..7b8e9da --- /dev/null +++ b/media/extra_grf/elrails.nfo @@ -0,0 +1,58 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// + -1 * 0 0C "Electrified rail by Michael Blunck" + -1 * 3 05 05 30 + -1 sprites/elrails.png 8bpp 66 8 32 16 -29 -2 normal + -1 sprites/elrails.png 8bpp 114 8 32 16 -1 -2 normal + -1 sprites/elrails.png 8bpp 162 8 32 1 -1 -2 normal + -1 sprites/elrails.png 8bpp 210 8 1 16 0 -3 normal + -1 sprites/elrails.png 8bpp 226 8 32 24 -29 -2 normal + -1 sprites/elrails.png 8bpp 274 8 32 9 -1 6 normal + -1 sprites/elrails.png 8bpp 322 8 32 9 -29 6 normal + -1 sprites/elrails.png 8bpp 370 8 32 24 -1 -2 normal + -1 sprites/elrails.png 8bpp 418 8 32 16 -29 -2 normal + -1 sprites/elrails.png 8bpp 466 8 32 16 -1 -2 normal + -1 sprites/elrails.png 8bpp 514 8 32 1 -1 -2 normal + -1 sprites/elrails.png 8bpp 562 8 1 16 0 -3 normal + -1 sprites/elrails.png 8bpp 578 8 32 24 -29 -2 normal + -1 sprites/elrails.png 8bpp 626 8 32 9 -1 6 normal + -1 sprites/elrails.png 8bpp 674 8 32 9 -29 6 normal + -1 sprites/elrails.png 8bpp 722 8 32 24 -1 -2 normal + -1 sprites/elrails.png 8bpp 2 56 32 16 -29 -2 normal + -1 sprites/elrails.png 8bpp 50 56 32 16 -1 -2 normal + -1 sprites/elrails.png 8bpp 98 56 32 1 -1 -2 normal + -1 sprites/elrails.png 8bpp 146 56 1 16 0 -3 normal + -1 sprites/elrails.png 8bpp 162 56 32 24 -29 -2 normal + -1 sprites/elrails.png 8bpp 210 56 32 9 -1 6 normal + -1 sprites/elrails.png 8bpp 258 56 32 9 -29 6 normal + -1 sprites/elrails.png 8bpp 306 56 32 24 -1 -2 normal + -1 sprites/elrails.png 8bpp 354 56 16 8 -29 6 normal + -1 sprites/elrails.png 8bpp 386 56 16 8 -1 -2 normal + -1 sprites/elrails.png 8bpp 418 56 16 8 -13 -2 normal + -1 sprites/elrails.png 8bpp 450 56 16 8 15 6 normal + -1 sprites/elrails.png 8bpp 482 56 8 16 -7 -14 normal + -1 sprites/elrails.png 8bpp 498 56 8 18 0 -17 normal + -1 sprites/elrails.png 8bpp 514 56 8 16 0 -14 normal + -1 sprites/elrails.png 8bpp 530 56 8 18 -7 -17 normal + -1 sprites/elrails.png 8bpp 546 56 2 16 0 -15 normal + -1 sprites/elrails.png 8bpp 562 56 2 18 0 -16 normal + -1 sprites/elrails.png 8bpp 578 56 8 16 0 -15 normal + -1 sprites/elrails.png 8bpp 594 56 8 16 -7 -15 normal + -1 sprites/elrails.png 8bpp 610 56 13 16 4 2 normal + -1 sprites/elrails.png 8bpp 642 56 20 16 0 2 normal + -1 sprites/elrails.png 8bpp 674 56 20 16 0 2 normal + -1 sprites/elrails.png 8bpp 706 56 20 16 0 2 normal + -1 sprites/elrails.png 8bpp 738 56 38 30 -3 -14 normal + -1 sprites/elrails.png 8bpp 2 104 72 44 -16 -8 normal + -1 sprites/elrails.png 8bpp 82 104 44 35 -21 -2 normal + -1 sprites/elrails.png 8bpp 146 104 72 44 -16 -35 normal + -1 sprites/elrails.png 8bpp 226 104 20 19 0 1 normal + -1 sprites/elrails.png 8bpp 258 104 32 32 0 0 normal + -1 sprites/elrails.png 8bpp 306 104 12 22 -9 -18 normal + -1 sprites/elrails.png 8bpp 338 104 12 22 -1 -18 normal diff --git a/media/extra_grf/elrails.png b/media/extra_grf/elrails.png new file mode 100644 index 0000000..a5166da Binary files /dev/null and b/media/extra_grf/elrails.png differ diff --git a/media/extra_grf/fix_graphics.nfo b/media/extra_grf/fix_graphics.nfo new file mode 100644 index 0000000..1144742 --- /dev/null +++ b/media/extra_grf/fix_graphics.nfo @@ -0,0 +1,376 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// + -1 * 0 0C "Fix bugs in the original graphics. By Addi and PaulC." + +// Non-toyland specific + -1 * 6 07 83 01 \7= 03 3D +// Fix missing wheels on the wood trucks + -1 * 14 0A 04 01 87 0C 01 89 0C 01 07 0E 01 09 0E + -1 sprites/fix_graphics.png 8bpp 82 8 22 16 -6 -7 normal + -1 sprites/fix_graphics.png 8bpp 114 8 22 16 -14 -7 normal + -1 sprites/fix_graphics.png 8bpp 146 8 22 16 -6 -7 normal + -1 sprites/fix_graphics.png 8bpp 178 8 22 16 -14 -7 normal +// Show correct graphics for various 3rd generation trucks + -1 * 5 0A 01 28 C4 0D + -1 sprites/fix_graphics.png 8bpp 226 8 8 18 -3 -10 normal + -1 sprites/fix_graphics.png 8bpp 242 8 20 16 -14 -7 normal + -1 sprites/fix_graphics.png 8bpp 274 8 28 12 -14 -6 normal + -1 sprites/fix_graphics.png 8bpp 322 8 20 16 -6 -7 normal + -1 sprites/fix_graphics.png 8bpp 354 8 8 18 -3 -10 normal + -1 sprites/fix_graphics.png 8bpp 370 8 20 16 -14 -7 normal + -1 sprites/fix_graphics.png 8bpp 402 8 28 12 -14 -6 normal + -1 sprites/fix_graphics.png 8bpp 450 8 20 16 -6 -7 normal + -1 sprites/fix_graphics.png 8bpp 482 8 8 18 -3 -10 normal + -1 sprites/fix_graphics.png 8bpp 498 8 20 16 -14 -7 normal + -1 sprites/fix_graphics.png 8bpp 530 8 28 12 -14 -6 normal + -1 sprites/fix_graphics.png 8bpp 578 8 20 16 -6 -7 normal + -1 sprites/fix_graphics.png 8bpp 610 8 8 18 -3 -10 normal + -1 sprites/fix_graphics.png 8bpp 626 8 20 16 -14 -7 normal + -1 sprites/fix_graphics.png 8bpp 658 8 28 12 -14 -6 normal + -1 sprites/fix_graphics.png 8bpp 706 8 20 16 -6 -7 normal + -1 sprites/fix_graphics.png 8bpp 738 8 8 18 -3 -10 normal + -1 sprites/fix_graphics.png 8bpp 754 8 22 16 -14 -7 normal + -1 sprites/fix_graphics.png 8bpp 2 40 28 12 -14 -6 normal + -1 sprites/fix_graphics.png 8bpp 50 40 22 16 -6 -7 normal + -1 sprites/fix_graphics.png 8bpp 82 40 8 18 -3 -10 normal + -1 sprites/fix_graphics.png 8bpp 98 40 22 16 -14 -7 normal + -1 sprites/fix_graphics.png 8bpp 130 40 28 12 -14 -6 normal + -1 sprites/fix_graphics.png 8bpp 178 40 22 16 -6 -7 normal + -1 sprites/fix_graphics.png 8bpp 210 40 8 18 -3 -10 normal + -1 sprites/fix_graphics.png 8bpp 226 40 22 16 -14 -7 normal + -1 sprites/fix_graphics.png 8bpp 258 40 28 12 -14 -6 normal + -1 sprites/fix_graphics.png 8bpp 306 40 22 16 -6 -7 normal + -1 sprites/fix_graphics.png 8bpp 338 40 8 18 -3 -10 normal + -1 sprites/fix_graphics.png 8bpp 354 40 22 16 -14 -7 normal + -1 sprites/fix_graphics.png 8bpp 386 40 28 12 -14 -6 normal + -1 sprites/fix_graphics.png 8bpp 434 40 22 16 -6 -7 normal + -1 sprites/fix_graphics.png 8bpp 466 40 8 18 -3 -10 normal + -1 sprites/fix_graphics.png 8bpp 482 40 20 16 -14 -7 normal + -1 sprites/fix_graphics.png 8bpp 514 40 28 12 -14 -6 normal + -1 sprites/fix_graphics.png 8bpp 562 40 20 16 -6 -7 normal + -1 sprites/fix_graphics.png 8bpp 594 40 8 18 -3 -10 normal + -1 sprites/fix_graphics.png 8bpp 610 40 20 16 -14 -7 normal + -1 sprites/fix_graphics.png 8bpp 642 40 28 12 -14 -6 normal + -1 sprites/fix_graphics.png 8bpp 690 40 20 16 -6 -7 normal +// Fix clipping on the 2nd generation paper truck + -1 * 14 0A 04 01 9D 0C 01 9F 0C 01 A1 0C 01 A3 0C + -1 sprites/fix_graphics.png 8bpp 738 40 22 16 -14 -7 normal + -1 sprites/fix_graphics.png 8bpp 770 40 22 16 -6 -7 normal + -1 sprites/fix_graphics.png 8bpp 2 72 22 16 -14 -7 normal + -1 sprites/fix_graphics.png 8bpp 34 72 22 16 -6 -7 normal +// Fix clipping on the 1st generation paper truck + -1 * 14 0A 04 01 5D 0D 01 5F 0D 01 61 0D 01 63 0D + -1 sprites/fix_graphics.png 8bpp 82 72 22 16 -14 -7 normal + -1 sprites/fix_graphics.png 8bpp 114 72 22 17 -5 -7 normal + -1 sprites/fix_graphics.png 8bpp 146 72 22 17 -14 -8 normal + -1 sprites/fix_graphics.png 8bpp 178 72 22 16 -6 -7 normal +// Fix clipping on the 3rd generation paper truck + -1 * 14 0A 04 01 1D 0E 01 1F 0E 01 21 0E 01 23 0E + -1 sprites/fix_graphics.png 8bpp 226 72 22 16 -14 -7 normal + -1 sprites/fix_graphics.png 8bpp 258 72 22 16 -6 -7 normal + -1 sprites/fix_graphics.png 8bpp 290 72 22 16 -14 -7 normal + -1 sprites/fix_graphics.png 8bpp 322 72 22 16 -6 -7 normal + +// Fix clipping on the toyland toy van in the German DOS graphics + -1 * 6 07 83 01 \7! 03 02 + -1 * 5 0A 01 01 5D 0C + -1 sprites/fix_graphics.png 8bpp 18 296 20 16 -14 -7 normal + +// Non-toyland specific + -1 * 6 07 83 01 \7= 03 08 +// Fix offsets for the monorail bridge heads + -1 * 8 0A 02 01 EA 10 02 EC 10 + -1 sprites/fix_graphics.png 8bpp 370 72 48 35 -23 -7 normal + -1 sprites/fix_graphics.png 8bpp 434 72 48 35 -23 -7 normal + -1 sprites/fix_graphics.png 8bpp 498 72 49 21 -24 3 normal +// Fix offsets for the maglev bridge heads + -1 * 8 0A 02 01 12 11 02 14 11 + -1 sprites/fix_graphics.png 8bpp 322 486 48 35 -23 -7 normal + -1 sprites/fix_graphics.png 8bpp 386 486 48 35 -23 -7 normal + -1 sprites/fix_graphics.png 8bpp 450 486 49 21 -24 3 normal + +// Toyland specific + -1 * 6 07 83 01 \7! 03 0F +// Fix offsets for the toyland monorail bridge heads + -1 * 8 0A 02 01 EA 10 02 EC 10 + -1 sprites/fix_graphics.png 8bpp 610 630 48 35 -23 -7 normal + -1 sprites/fix_graphics.png 8bpp 674 630 48 35 -23 -7 normal + -1 sprites/fix_graphics.png 8bpp 738 630 49 21 -24 3 normal +// Fix offsets for the toyland maglev bridge heads + -1 * 8 0A 02 01 12 11 02 14 11 + -1 sprites/fix_graphics.png 8bpp 18 678 48 35 -23 -7 normal + -1 sprites/fix_graphics.png 8bpp 82 678 48 35 -23 -7 normal + -1 sprites/fix_graphics.png 8bpp 146 678 49 21 -24 3 normal +// Fix colours for toyland maglev junction overlays + -1 * 5 0A 01 06 91 04 + -1 sprites/fix_graphics.png 8bpp 338 630 30 16 -14 8 normal + -1 sprites/fix_graphics.png 8bpp 386 630 30 16 -14 8 normal + -1 sprites/fix_graphics.png 8bpp 434 630 40 7 -19 4 normal + -1 sprites/fix_graphics.png 8bpp 482 630 40 7 -19 20 normal + -1 sprites/fix_graphics.png 8bpp 530 630 12 19 11 6 normal + -1 sprites/fix_graphics.png 8bpp 562 630 12 19 -21 6 normal + +// Fix transparency of cinema + -1 * 5 0A 01 02 34 11 + -1 sprites/fix_graphics.png 8bpp 578 72 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 658 72 50 47 -28 -20 normal + +// Fix misaligned undergrounds for temperate monorail + -1 * 6 07 83 01 \7! 00 06 + -1 * 5 0A 01 05 4C 04 + -1 sprites/fix_graphics.png 8bpp 2 136 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 82 136 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 162 136 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 242 136 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 322 136 64 31 -31 0 normal + +// Fix misaligned undergrounds for arctic monorail + -1 * 6 07 83 01 \7! 01 06 + -1 * 5 0A 01 05 4C 04 + -1 sprites/fix_graphics.png 8bpp 434 136 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 514 136 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 594 136 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 674 136 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 2 184 64 31 -31 0 normal + +// Fix misaligned undergrounds for tropical/desert monorail/maglev + -1 * 6 07 83 01 \7! 02 10 + -1 * 11 0A 03 05 4C 04 05 66 04 05 B8 04 + -1 sprites/fix_graphics.png 8bpp 114 184 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 194 184 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 274 184 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 354 184 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 434 184 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 514 184 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 594 184 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 674 184 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 2 232 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 82 232 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 162 232 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 242 232 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 322 232 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 402 232 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 482 232 64 31 -31 0 normal + +// Fix misaligned X crossing for snow-covered monorail + -1 * 6 07 83 01 \7! 01 02 + -1 * 5 0A 01 01 65 04 + -1 sprites/fix_graphics.png 8bpp 594 232 64 31 -31 0 normal + +// Fix offsets for the tropical house + -1 * 5 0A 01 01 FF 11 + -1 sprites/fix_graphics.png 8bpp 706 232 64 47 -31 -16 normal + +// Graphics metadata pixel higher than actual graphics + -1 * 6 12 01 00 01 AC E2 + -1 sprites/fix_graphics.png 8bpp 66 296 9 10 0 0 normal + +// Non-toyland specific + -1 * 6 07 83 01 \7= 03 0A +// Fix offsets for the tubular bridge pillars + -1 * 5 0A 01 04 05 0A + -1 sprites/fix_graphics.png 8bpp 98 296 4 9 2 -1 normal + -1 sprites/fix_graphics.png 8bpp 114 296 4 9 2 -1 normal + -1 sprites/fix_graphics.png 8bpp 130 296 4 9 -4 0 normal + -1 sprites/fix_graphics.png 8bpp 146 296 4 9 -4 0 normal +// Fix offsets for the cantilever bridge pillars + -1 * 5 0A 01 04 DD 09 + -1 sprites/fix_graphics.png 8bpp 178 296 10 11 2 -3 normal + -1 sprites/fix_graphics.png 8bpp 194 296 10 12 2 -2 normal + -1 sprites/fix_graphics.png 8bpp 210 296 10 11 -10 -1 normal + -1 sprites/fix_graphics.png 8bpp 226 296 10 11 -10 -1 normal + +// Toyland specific + -1 * 6 07 83 01 \7! 03 0A +// Fix offsets for the toyland tubular bridge pillars + -1 * 5 0A 01 04 05 0A + -1 sprites/fix_graphics.png 8bpp 248 296 4 9 2 -1 normal + -1 sprites/fix_graphics.png 8bpp 264 296 4 9 2 -1 normal + -1 sprites/fix_graphics.png 8bpp 280 296 4 9 -4 0 normal + -1 sprites/fix_graphics.png 8bpp 296 296 4 9 -4 0 normal +// Fix offsets for the toyland cantilever bridge pillars + -1 * 5 0A 01 04 DD 09 + -1 sprites/fix_graphics.png 8bpp 328 296 10 11 2 -3 normal + -1 sprites/fix_graphics.png 8bpp 344 296 10 12 2 -2 normal + -1 sprites/fix_graphics.png 8bpp 360 296 10 11 -10 -1 normal + -1 sprites/fix_graphics.png 8bpp 376 296 10 11 -10 -1 normal + +// Wrong, non-translated colours in tubular bridge in 'normal' climates +// Toyland has separate sprites which are not colour translated, thus +// this does not apply there; +// Pillars are changed for all climates further up + -1 * 6 07 83 01 \7= 03 \b22 +// Main tubular bridge sprites + -1 * 5 0A 01 \b6 \w2559 + -1 sprites/fix_graphics.png 8bpp 2 330 32 40 -30 -26 normal + -1 sprites/fix_graphics.png 8bpp 52 330 44 50 -42 -26 normal + -1 sprites/fix_graphics.png 8bpp 116 330 46 45 -42 -21 normal + -1 sprites/fix_graphics.png 8bpp 180 330 46 45 -2 -20 normal + -1 sprites/fix_graphics.png 8bpp 244 330 44 50 0 -25 normal + -1 sprites/fix_graphics.png 8bpp 308 330 32 41 0 -25 normal +// start rail bridge + -1 * 5 0A 01 01 \w2569 + -1 sprites/fix_graphics.png 8bpp 350 330 52 29 -25 -4 normal +// start rail + road bridge + -1 * 5 0A 01 02 \w2574 + -1 sprites/fix_graphics.png 8bpp 420 330 50 29 -25 -4 normal + -1 sprites/fix_graphics.png 8bpp 489 330 52 29 -25 -4 normal +// start road + monorail bridge + -1 * 5 0A 01 02 \w2580 + -1 sprites/fix_graphics.png 8bpp 559 330 50 29 -25 -4 normal + -1 sprites/fix_graphics.png 8bpp 629 330 52 29 -25 -4 normal +// start monrail + maglev bridge + -1 * 5 0A 01 02 \w2586 + -1 sprites/fix_graphics.png 8bpp 699 330 50 29 -25 -4 normal + -1 sprites/fix_graphics.png 8bpp 489 283 52 29 -25 -4 normal +// start maglev bridge + -1 * 5 0A 01 01 \w2592 + -1 sprites/fix_graphics.png 8bpp 559 283 50 29 -25 -4 normal +// GUI sprite + -1 * 5 0A 01 01 \w2600 + -1 sprites/fix_graphics.png 8bpp 433 298 40 15 0 5 normal + +// Remove road markings from tropical rail crossings + -1 * 6 07 83 01 \7! 02 19 + -1 * 14 0A 04 04 5A 05 08 62 05 08 6E 05 04 7A 05 + -1 sprites/fix_graphics.png 8bpp 2 390 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 82 390 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 162 390 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 242 390 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 322 390 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 402 390 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 482 390 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 562 390 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 642 390 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 722 390 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 2 438 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 82 438 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 162 438 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 242 438 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 322 438 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 402 438 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 482 438 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 562 438 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 642 438 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 722 438 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 2 486 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 82 486 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 162 486 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 242 486 64 31 -31 0 normal + +// Fix transparency of steel mill + -1 * 5 0A 01 06 46 08 + -1 sprites/fix_graphics.png 8bpp 162 870 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 242 870 64 51 -31 -21 normal + -1 sprites/fix_graphics.png 8bpp 322 870 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 402 870 49 58 -29 -29 normal + -1 sprites/fix_graphics.png 8bpp 466 870 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 546 870 45 42 -18 -12 normal + -1 * 5 0A 01 0A 4D 08 + -1 sprites/fix_graphics.png 8bpp 610 486 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 690 486 59 61 -31 -33 normal + -1 sprites/fix_graphics.png 8bpp 2 566 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 82 566 51 50 -25 -21 normal + -1 sprites/fix_graphics.png 8bpp 606 870 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 686 870 64 46 -31 -16 normal + -1 sprites/fix_graphics.png 8bpp 2 945 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 82 945 50 51 -29 -21 normal + -1 sprites/fix_graphics.png 8bpp 146 945 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 226 945 47 42 -18 -12 normal + -1 * 5 0A 01 04 58 08 + -1 sprites/fix_graphics.png 8bpp 162 566 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 242 566 59 52 -31 -24 normal + -1 sprites/fix_graphics.png 8bpp 306 566 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 386 566 51 44 -25 -15 normal + +// Fix transparency of oil well + -1 * 5 0A 01 07 7D 08 + -1 sprites/fix_graphics.png 8bpp 2 630 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 482 566 31 50 -11 -28 normal + -1 sprites/fix_graphics.png 8bpp 530 566 31 47 -11 -25 normal + -1 sprites/fix_graphics.png 8bpp 578 566 31 47 -11 -25 normal + -1 sprites/fix_graphics.png 8bpp 626 566 31 47 -11 -25 normal + -1 sprites/fix_graphics.png 8bpp 674 566 31 49 -11 -27 normal + -1 sprites/fix_graphics.png 8bpp 722 566 31 52 -11 -30 normal + -1 * 6 07 83 01 \7! 01 02 + -1 * 5 0A 01 01 7D 08 + -1 sprites/fix_graphics.png 8bpp 114 630 64 31 -31 0 normal + -1 * 6 07 83 01 \7! 02 02 + -1 * 5 0A 01 01 7D 08 + -1 sprites/fix_graphics.png 8bpp 226 630 64 31 -31 0 normal + +// Fix city airport's grass for temperate + -1 * 6 07 83 01 \7! 00 0A + -1 * 5 0A 01 09 4C 0A + -1 sprites/fix_graphics.png 8bpp 242 678 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 322 678 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 402 678 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 482 678 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 562 678 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 642 678 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 722 678 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 2 726 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 82 726 64 31 -31 0 normal + +// Fix city airport's grass for arctic + -1 * 6 07 83 01 \7! 01 0A + -1 * 5 0A 01 09 4C 0A + -1 sprites/fix_graphics.png 8bpp 194 726 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 274 726 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 354 726 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 434 726 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 514 726 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 594 726 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 674 726 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 2 774 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 82 774 64 31 -31 0 normal + +// Fix city airport's grass for tropical + -1 * 6 07 83 01 \7! 02 0A + -1 * 5 0A 01 09 4C 0A + -1 sprites/fix_graphics.png 8bpp 194 774 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 274 774 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 354 774 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 434 774 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 514 774 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 594 774 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 674 774 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 2 822 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 82 822 64 31 -31 0 normal + +// Fix city airport's grass for toyland + -1 * 6 07 83 01 \7! 03 0A + -1 * 5 0A 01 09 4C 0A + -1 sprites/fix_graphics.png 8bpp 194 822 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 274 822 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 354 822 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 434 822 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 514 822 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 594 822 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 674 822 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 2 870 64 31 -31 0 normal + -1 sprites/fix_graphics.png 8bpp 82 870 64 31 -31 0 normal + +// Wrong, non-translated colours in arctic buildings + -1 * 8 0A 02 01 1F 06 01 DB 11 + -1 sprites/fix_graphics.png 8bpp 305 945 59 29 -29 -12 normal + -1 sprites/fix_graphics.png 8bpp 369 945 59 29 -29 -12 normal + -1 * 8 0A 02 01 76 11 01 E6 11 + -1 sprites/fix_graphics.png 8bpp 449 945 64 69 -31 -38 normal + -1 sprites/fix_graphics.png 8bpp 529 945 64 69 -31 -38 normal + -1 * 8 0A 02 02 7E 11 01 E1 11 + -1 sprites/fix_graphics.png 8bpp 625 945 54 75 -25 -47 normal + -1 sprites/fix_graphics.png 8bpp 2 1037 54 75 -25 -47 normal + -1 sprites/fix_graphics.png 8bpp 66 1037 54 75 -25 -47 normal + +// Fix buoy in-game; don't show black outline + -1 * 4 01 05 01 \b1 + -1 sprites/fix_graphics.png 8bpp 575 490 7 11 7 4 normal + -1 * 7 02 05 17 01 00 00 00 + -1 * 7 03 05 01 08 00 17 00 diff --git a/media/extra_grf/fix_graphics.png b/media/extra_grf/fix_graphics.png new file mode 100644 index 0000000..1dc7bad Binary files /dev/null and b/media/extra_grf/fix_graphics.png differ diff --git a/media/extra_grf/flags.nfo b/media/extra_grf/flags.nfo new file mode 100644 index 0000000..ab792ef --- /dev/null +++ b/media/extra_grf/flags.nfo @@ -0,0 +1,46 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// + -1 * 0 0C "Flag graphics" + -1 * 3 05 14 24 + -1 sprites/flags.png 8bpp 34 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 50 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 66 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 82 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 98 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 114 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 130 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 146 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 162 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 178 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 194 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 210 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 226 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 242 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 258 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 274 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 290 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 306 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 322 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 338 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 354 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 370 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 386 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 402 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 418 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 434 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 450 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 466 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 482 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 498 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 514 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 530 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 546 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 562 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 578 8 11 8 0 0 normal + -1 sprites/flags.png 8bpp 594 8 11 8 0 0 normal diff --git a/media/extra_grf/flags.png b/media/extra_grf/flags.png new file mode 100644 index 0000000..2e0401f Binary files /dev/null and b/media/extra_grf/flags.png differ diff --git a/media/extra_grf/foundations.nfo b/media/extra_grf/foundations.nfo new file mode 100644 index 0000000..437fcd9 --- /dev/null +++ b/media/extra_grf/foundations.nfo @@ -0,0 +1,377 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// + -1 * 0 0C "Foundations. Non-halftile ones by Marcin Grzegorczyk" + -1 * 6 07 83 01 \7! 00 5B + -1 * 3 05 06 5A + -1 sprites/foundations.png 8bpp 82 8 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 8 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 8 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 8 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 8 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 8 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 8 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 8 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 8 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 72 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 72 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 72 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 72 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 72 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 72 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 72 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 72 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 72 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 72 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 136 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 136 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 136 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 136 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 136 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 136 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 136 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 136 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 136 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 136 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 200 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 200 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 200 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 200 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 200 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 200 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 200 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 200 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 200 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 200 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 264 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 264 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 264 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 264 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 264 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 264 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 264 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 264 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 264 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 264 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 328 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 328 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 328 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 328 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 328 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 328 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 328 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 328 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 328 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 328 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 392 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 392 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 392 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 392 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 392 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 392 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 392 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 392 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 392 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 392 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 456 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 456 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 456 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 456 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 456 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 456 64 40 -15 -17 normal + -1 sprites/foundations.png 8bpp 482 456 64 33 -31 -25 normal + -1 sprites/foundations.png 8bpp 562 456 64 40 -47 -17 normal + -1 sprites/foundations.png 8bpp 642 456 64 33 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 456 64 40 -15 -17 normal + -1 sprites/foundations.png 8bpp 2 520 64 33 -31 -25 normal + -1 sprites/foundations.png 8bpp 82 520 64 40 -47 -17 normal + -1 sprites/foundations.png 8bpp 162 520 64 33 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 520 64 40 -15 -17 normal + -1 sprites/foundations.png 8bpp 322 520 64 33 -31 -25 normal + -1 sprites/foundations.png 8bpp 402 520 64 40 -47 -17 normal + -1 sprites/foundations.png 8bpp 482 520 64 33 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 520 64 40 -15 -17 normal + -1 sprites/foundations.png 8bpp 642 520 64 33 -31 -25 normal + -1 sprites/foundations.png 8bpp 722 520 64 40 -47 -17 normal + -1 sprites/foundations.png 8bpp 2 584 64 33 -31 -9 normal + -1 * 6 07 83 01 \7! 01 5B + -1 * 3 05 06 5A + -1 sprites/foundations.png 8bpp 114 584 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 194 584 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 274 584 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 354 584 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 434 584 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 514 584 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 594 584 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 674 584 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 648 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 648 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 648 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 648 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 648 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 648 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 648 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 648 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 648 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 648 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 712 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 712 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 712 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 712 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 712 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 712 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 712 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 712 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 712 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 712 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 776 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 776 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 776 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 776 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 776 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 776 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 776 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 776 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 776 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 776 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 840 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 840 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 840 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 840 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 840 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 840 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 840 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 840 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 840 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 840 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 904 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 904 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 904 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 904 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 904 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 904 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 904 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 904 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 904 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 904 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 968 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 968 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 968 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 968 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 968 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 968 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 968 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 968 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 968 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 968 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 1032 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 1032 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 1032 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 1032 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 1032 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 1032 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 1032 64 40 -15 -17 normal + -1 sprites/foundations.png 8bpp 562 1032 64 33 -31 -25 normal + -1 sprites/foundations.png 8bpp 642 1032 64 40 -47 -17 normal + -1 sprites/foundations.png 8bpp 722 1032 64 33 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 1096 64 40 -15 -17 normal + -1 sprites/foundations.png 8bpp 82 1096 64 33 -31 -25 normal + -1 sprites/foundations.png 8bpp 162 1096 64 40 -47 -17 normal + -1 sprites/foundations.png 8bpp 242 1096 64 33 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 1096 64 40 -15 -17 normal + -1 sprites/foundations.png 8bpp 402 1096 64 33 -31 -25 normal + -1 sprites/foundations.png 8bpp 482 1096 64 40 -47 -17 normal + -1 sprites/foundations.png 8bpp 562 1096 64 33 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 1096 64 40 -15 -17 normal + -1 sprites/foundations.png 8bpp 722 1096 64 33 -31 -25 normal + -1 sprites/foundations.png 8bpp 2 1160 64 40 -47 -17 normal + -1 sprites/foundations.png 8bpp 82 1160 64 33 -31 -9 normal + -1 * 6 07 83 01 \7! 02 5B + -1 * 3 05 06 5A + -1 sprites/foundations.png 8bpp 194 1160 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 274 1160 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 354 1160 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 434 1160 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 514 1160 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 594 1160 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 674 1160 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 1224 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 1224 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 1224 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 1224 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 1224 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 1224 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 1224 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 1224 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 1224 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 1224 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 1288 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 1288 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 1288 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 1288 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 1288 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 1288 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 1288 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 1288 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 1288 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 1288 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 1352 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 1352 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 1352 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 1352 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 1352 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 1352 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 1352 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 1352 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 1352 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 1352 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 1416 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 1416 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 1416 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 1416 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 1416 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 1416 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 1416 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 1416 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 1416 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 1416 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 1480 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 1480 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 1480 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 1480 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 1480 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 1480 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 1480 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 1480 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 1480 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 1480 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 1544 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 1544 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 1544 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 1544 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 1544 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 1544 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 1544 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 1544 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 1544 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 1544 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 1608 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 1608 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 1608 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 1608 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 1608 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 1608 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 1608 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 1608 64 40 -15 -17 normal + -1 sprites/foundations.png 8bpp 642 1608 64 33 -31 -25 normal + -1 sprites/foundations.png 8bpp 722 1608 64 40 -47 -17 normal + -1 sprites/foundations.png 8bpp 2 1672 64 33 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 1672 64 40 -15 -17 normal + -1 sprites/foundations.png 8bpp 162 1672 64 33 -31 -25 normal + -1 sprites/foundations.png 8bpp 242 1672 64 40 -47 -17 normal + -1 sprites/foundations.png 8bpp 322 1672 64 33 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 1672 64 40 -15 -17 normal + -1 sprites/foundations.png 8bpp 482 1672 64 33 -31 -25 normal + -1 sprites/foundations.png 8bpp 562 1672 64 40 -47 -17 normal + -1 sprites/foundations.png 8bpp 642 1672 64 33 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 1672 64 40 -15 -17 normal + -1 sprites/foundations.png 8bpp 2 1736 64 33 -31 -25 normal + -1 sprites/foundations.png 8bpp 82 1736 64 40 -47 -17 normal + -1 sprites/foundations.png 8bpp 162 1736 64 33 -31 -9 normal + -1 * 6 07 83 01 \7! 03 5B + -1 * 3 05 06 5A + -1 sprites/foundations.png 8bpp 274 1736 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 354 1736 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 434 1736 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 514 1736 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 594 1736 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 674 1736 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 1800 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 1800 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 1800 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 1800 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 1800 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 1800 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 1800 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 1800 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 1800 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 1800 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 1864 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 1864 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 1864 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 1864 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 1864 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 1864 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 1864 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 1864 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 1864 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 1864 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 1928 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 1928 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 1928 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 1928 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 1928 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 1928 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 1928 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 1928 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 1928 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 1928 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 1992 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 1992 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 1992 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 1992 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 1992 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 1992 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 1992 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 1992 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 1992 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 1992 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 2056 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 2056 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 2056 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 2056 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 2056 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 2056 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 2056 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 2056 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 2056 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 2056 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 2120 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 2120 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 2120 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 2120 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 2120 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 2120 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 2120 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 2120 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 2120 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 722 2120 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 2184 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 82 2184 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 2184 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 242 2184 64 32 -31 -9 normal + -1 sprites/foundations.png 8bpp 322 2184 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 402 2184 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 2184 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 562 2184 64 40 -31 -9 normal + -1 sprites/foundations.png 8bpp 642 2184 64 40 -15 -17 normal + -1 sprites/foundations.png 8bpp 722 2184 64 33 -31 -25 normal + -1 sprites/foundations.png 8bpp 2 2248 64 40 -47 -17 normal + -1 sprites/foundations.png 8bpp 82 2248 64 33 -31 -9 normal + -1 sprites/foundations.png 8bpp 162 2248 64 40 -15 -17 normal + -1 sprites/foundations.png 8bpp 242 2248 64 33 -31 -25 normal + -1 sprites/foundations.png 8bpp 322 2248 64 40 -47 -17 normal + -1 sprites/foundations.png 8bpp 402 2248 64 33 -31 -9 normal + -1 sprites/foundations.png 8bpp 482 2248 64 40 -15 -17 normal + -1 sprites/foundations.png 8bpp 562 2248 64 33 -31 -25 normal + -1 sprites/foundations.png 8bpp 642 2248 64 40 -47 -17 normal + -1 sprites/foundations.png 8bpp 722 2248 64 33 -31 -9 normal + -1 sprites/foundations.png 8bpp 2 2312 64 40 -15 -17 normal + -1 sprites/foundations.png 8bpp 82 2312 64 33 -31 -25 normal + -1 sprites/foundations.png 8bpp 162 2312 64 40 -47 -17 normal + -1 sprites/foundations.png 8bpp 242 2312 64 33 -31 -9 normal diff --git a/media/extra_grf/foundations.png b/media/extra_grf/foundations.png new file mode 100644 index 0000000..c05b80e Binary files /dev/null and b/media/extra_grf/foundations.png differ diff --git a/media/extra_grf/mono.nfo b/media/extra_grf/mono.nfo new file mode 100644 index 0000000..a5f0fe5 --- /dev/null +++ b/media/extra_grf/mono.nfo @@ -0,0 +1,240 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// + -1 * 0 0C "Monospaced characters (Liberation Mono)" + -1 * 0 12 01 03 60 20 00 + -1 sprites/mono.png 8bpp 10 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 25 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 40 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 55 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 70 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 85 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 100 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 115 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 130 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 145 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 160 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 175 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 190 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 205 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 220 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 235 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 250 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 265 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 280 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 295 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 310 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 325 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 340 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 355 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 370 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 385 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 400 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 415 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 430 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 445 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 460 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 475 30 7 13 0 0 normal + -1 sprites/mono.png 8bpp 10 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 25 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 40 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 55 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 70 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 85 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 100 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 115 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 130 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 145 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 160 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 175 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 190 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 205 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 220 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 235 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 250 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 265 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 280 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 295 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 310 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 325 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 340 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 355 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 370 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 385 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 400 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 415 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 430 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 445 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 460 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 475 50 7 13 0 0 normal + -1 sprites/mono.png 8bpp 10 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 25 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 40 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 55 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 70 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 85 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 100 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 115 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 130 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 145 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 160 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 175 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 190 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 205 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 220 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 235 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 250 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 265 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 280 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 295 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 310 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 325 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 340 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 355 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 370 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 385 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 400 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 415 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 430 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 445 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 460 70 7 13 0 0 normal + -1 sprites/mono.png 8bpp 475 70 7 13 0 0 normal + + -1 * 0 12 01 03 80 80 00 + -1 sprites/mono.png 8bpp 10 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 25 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 40 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 55 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 70 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 85 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 100 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 115 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 130 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 145 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 160 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 175 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 190 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 205 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 220 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 235 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 250 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 265 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 280 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 295 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 310 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 325 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 340 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 355 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 370 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 385 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 400 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 415 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 430 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 445 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 460 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 475 90 7 13 0 0 normal + -1 sprites/mono.png 8bpp 10 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 25 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 40 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 55 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 70 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 85 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 100 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 115 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 130 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 145 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 160 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 175 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 190 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 205 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 220 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 235 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 250 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 265 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 280 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 295 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 310 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 325 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 340 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 355 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 370 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 385 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 400 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 415 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 430 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 445 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 460 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 475 110 7 13 0 0 normal + -1 sprites/mono.png 8bpp 10 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 25 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 40 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 55 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 70 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 85 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 100 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 115 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 130 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 145 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 160 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 175 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 190 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 205 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 220 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 235 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 250 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 265 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 280 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 295 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 310 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 325 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 340 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 355 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 370 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 385 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 400 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 415 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 430 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 445 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 460 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 475 130 7 13 0 0 normal + -1 sprites/mono.png 8bpp 10 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 25 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 40 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 55 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 70 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 85 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 100 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 115 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 130 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 145 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 160 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 175 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 190 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 205 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 220 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 235 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 250 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 265 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 280 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 295 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 310 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 325 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 340 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 355 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 370 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 385 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 400 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 415 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 430 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 445 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 460 150 7 13 0 0 normal + -1 sprites/mono.png 8bpp 475 150 7 13 0 0 normal + +//U+0178 Latin Capital Letter Y With Diaeresis (only needed for mono as it is in the base set, but relocated by some code) + -1 * 0 12 01 03 01 78 01 + -1 sprites/mono.png 8bpp 370 230 7 13 0 0 normal diff --git a/media/extra_grf/mono.png b/media/extra_grf/mono.png new file mode 100644 index 0000000..fb52e1e Binary files /dev/null and b/media/extra_grf/mono.png differ diff --git a/media/extra_grf/oneway.nfo b/media/extra_grf/oneway.nfo new file mode 100644 index 0000000..7426421 --- /dev/null +++ b/media/extra_grf/oneway.nfo @@ -0,0 +1,16 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// + -1 * 0 0C "One way road graphics" + -1 * 3 05 09 06 + -1 sprites/oneway.png 8bpp 34 8 24 16 -12 -8 normal + -1 sprites/oneway.png 8bpp 66 8 24 16 -12 -8 normal + -1 sprites/oneway.png 8bpp 98 8 24 16 -12 -8 normal + -1 sprites/oneway.png 8bpp 130 8 24 16 -12 -8 normal + -1 sprites/oneway.png 8bpp 162 8 24 16 -12 -8 normal + -1 sprites/oneway.png 8bpp 194 8 24 16 -12 -8 normal diff --git a/media/extra_grf/oneway.png b/media/extra_grf/oneway.png new file mode 100644 index 0000000..15542af Binary files /dev/null and b/media/extra_grf/oneway.png differ diff --git a/media/extra_grf/openttd.nfo b/media/extra_grf/openttd.nfo new file mode 100644 index 0000000..66149a3 --- /dev/null +++ b/media/extra_grf/openttd.nfo @@ -0,0 +1,107 @@ +// Automatically generated by GRFCODEC. Do not modify! +// (Info version 32) +// Format: spritenum imagefile depth xpos ypos xsize ysize xrel yrel zoom flags +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// +// Sources for OpenTTD's required base graphics. +// Checks whether the correct version of OpenTTD is used before +// allowing it to be used. +// + +// +// Number of sprites, it is wrong, but GRFcodec automagically gets it right. +// + 0 * 4 00 00 00 00 + + +// +// Check whether we are running OTTD or not. +// + -1 * 0 07 9D 04 \7= 01 00 00 00 01 + -1 * 0 0B 03 7F FF 80 " is not for TTDPatch. Use ttdpatch(w).grf." 00 + + +// +// Check for OTTD's version number +// + +// First step... Variable A1 might not exist. If that's the case it always +// skips. As we do not want to skip out of the whole testing, we skip over +// the real version check. + -1 * 0 07 A1 04 \7= FF FF FF FF 02 + +// Real version check. + -1 * 0 07 A1 04 \7> \w20304 01 01 03 + +// If the version check is supported, the string is translateable via OpenTTD +// itself. Use it!. + + -1 * 0 0B 03 7F 06 "1.1 (or trunk r20304)" 00 + +// Some OTTD versions before r11130 did support Action B, so use the English +// phrase there + -1 * 0 0B 03 7F FF "Requires OpenTTD version 1.1 (or trunk r20304) or better." 00 + +// Final fallback. No Action B support, just skip to the end of the file. + -1 * 0 07 A1 04 \7= FF FF FF FF 00 + +// We are a DOS paletted NewGRF, so tell OpenTTD that. Then it can actually +// do the right thing. Yay for that feature as that means no duplicate NewGRF! + -1 * 0 14 + "C" "INFO" + "B" "PALS" \w1 "D" + 00 + 00 + +// GRF ID, must start with FF so it gets ignored + -1 * 0 08 08 FF "OTT" + +// Name of the GRF + "OpenTTD's base graphics " 00 + +// Description of the GRF. + "License: GNU General Public License version 2" 0D + "Marcin Grzegorczyk: non-halftile foundations" 0D + "Michael Blunck: catenary, signals" 0D + "George: canals" 0D + "David Dallaston: tram tracks" 0D + "Jonathan G. Rennison: aqueducts" 0D + "Bilbo, Jasper Vries: font" 0D + "Andrew Parkhouse: rivers" 0D + "OpenTTD developers: other graphics" 00 + +// +// The real data of the GRF is acquired from several subfiles. +// +#include "2ccmap.nfo" +#include "signals.nfo" +#include "elrails.nfo" +#include "foundations.nfo" +#include "canals.nfo" +#include "oneway.nfo" +#include "tramtracks.nfo" +#include "shore.nfo" +#include "sloped_tracks.nfo" +#include "airports.nfo" +#include "roadstops.nfo" +#include "aqueduct.nfo" +#include "autorail.nfo" +#include "flags.nfo" +#include "openttdgui.nfo" +#include "airport_preview.nfo" +#include "chars.nfo" +#include "mono.nfo" +#include "fix_graphics.nfo" +#include "rivers/rapids.nfo" +#include "rivers/temperate.nfo" +#include "rivers/arctic.nfo" +#include "rivers/tropic.nfo" +#include "rivers/toyland.nfo" +#include "tunnel_portals.nfo" +#include "palette.nfo" diff --git a/media/extra_grf/openttdgui.nfo b/media/extra_grf/openttdgui.nfo new file mode 100644 index 0000000..1b17b86 --- /dev/null +++ b/media/extra_grf/openttdgui.nfo @@ -0,0 +1,185 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// + -1 * 0 0C "OpenTTD GUI graphics" + -1 * 3 05 15 \b 175 // OPENTTD_SPRITE_COUNT + -1 sprites/openttdgui.png 8bpp 66 8 64 31 -31 7 normal + -1 sprites/openttdgui.png 8bpp 146 8 64 31 -31 7 normal + -1 sprites/openttdgui.png 8bpp 226 8 64 31 -31 7 normal + -1 sprites/openttdgui.png 8bpp 306 8 64 31 -31 7 normal + -1 sprites/openttdgui.png 8bpp 386 8 64 31 -31 -1 normal + -1 sprites/openttdgui.png 8bpp 466 8 64 39 -31 -1 normal + -1 sprites/openttdgui.png 8bpp 546 8 64 31 -31 -1 normal + -1 sprites/openttdgui.png 8bpp 626 8 64 23 -31 7 normal + -1 sprites/openttdgui.png 8bpp 706 8 64 31 -31 7 normal + -1 sprites/openttdgui.png 8bpp 2 72 64 23 -31 7 normal + -1 sprites/openttdgui.png 8bpp 82 72 64 31 -31 7 normal + -1 sprites/openttdgui.png 8bpp 162 72 64 39 -31 -1 normal + -1 sprites/openttdgui.png 8bpp 242 72 23 26 0 0 normal + -1 sprites/openttdgui.png 8bpp 274 72 24 26 0 0 normal + -1 sprites/openttdgui.png 8bpp 306 72 4 8 28 16 normal + -1 sprites/openttdgui.png 8bpp 322 72 4 9 0 1 normal + -1 sprites/openttdgui.png 8bpp 338 72 32 23 0 1 normal + -1 sprites/openttdgui.png 8bpp 386 72 4 8 -31 15 normal + -1 sprites/openttdgui.png 8bpp 402 72 4 9 -3 0 normal + -1 sprites/openttdgui.png 8bpp 418 72 32 23 -31 0 normal + -1 sprites/openttdgui.png 8bpp 466 72 4 8 28 16 normal + -1 sprites/openttdgui.png 8bpp 482 72 4 9 0 1 normal + -1 sprites/openttdgui.png 8bpp 498 72 32 23 0 1 normal + -1 sprites/openttdgui.png 8bpp 546 72 4 8 -31 15 normal + -1 sprites/openttdgui.png 8bpp 562 72 4 9 -3 0 normal + -1 sprites/openttdgui.png 8bpp 578 72 32 23 -31 0 normal + -1 sprites/openttdgui.png 8bpp 626 72 4 8 28 16 normal + -1 sprites/openttdgui.png 8bpp 642 72 4 9 0 1 normal + -1 sprites/openttdgui.png 8bpp 658 72 32 23 0 1 normal + -1 sprites/openttdgui.png 8bpp 706 72 4 8 -31 15 normal + -1 sprites/openttdgui.png 8bpp 722 72 4 9 -3 0 normal + -1 sprites/openttdgui.png 8bpp 738 72 32 23 -31 0 normal + -1 sprites/openttdgui.png 8bpp 786 72 4 8 28 16 normal + -1 sprites/openttdgui.png 8bpp 2 136 4 9 0 1 normal + -1 sprites/openttdgui.png 8bpp 18 136 32 23 0 1 normal + -1 sprites/openttdgui.png 8bpp 66 136 4 8 -31 15 normal + -1 sprites/openttdgui.png 8bpp 82 136 4 9 -3 0 normal + -1 sprites/openttdgui.png 8bpp 98 136 32 23 -31 0 normal + -1 sprites/openttdgui.png 8bpp 146 136 10 10 0 0 normal + -1 sprites/openttdgui.png 8bpp 162 136 8 8 0 0 normal + -1 sprites/openttdgui.png 8bpp 178 136 7 9 0 0 normal + -1 sprites/openttdgui.png 8bpp 194 136 9 7 0 0 normal + -1 sprites/openttdgui.png 8bpp 210 136 9 7 0 0 normal + -1 sprites/openttdgui.png 8bpp 226 136 10 10 0 0 normal + -1 sprites/openttdgui.png 8bpp 242 136 7 7 0 0 normal + -1 sprites/openttdgui.png 8bpp 258 136 7 4 1 2 normal + -1 sprites/openttdgui.png 8bpp 274 136 7 4 1 2 normal + -1 sprites/openttdgui.png 8bpp 290 136 4 7 1 1 normal + -1 sprites/openttdgui.png 8bpp 306 136 4 7 2 1 normal + -1 sprites/openttdgui.png 8bpp 322 136 8 8 1 1 normal + -1 sprites/openttdgui.png 8bpp 338 136 9 9 0 0 normal + -1 sprites/openttdgui.png 8bpp 354 136 7 8 0 0 normal + -1 sprites/openttdgui.png 8bpp 370 136 8 8 0 0 normal + -1 sprites/openttdgui.png 8bpp 386 136 20 13 0 4 normal + -1 sprites/openttdgui.png 8bpp 418 136 56 36 0 0 normal + -1 sprites/openttdgui.png 8bpp 482 136 20 20 0 0 normal + -1 sprites/openttdgui.png 8bpp 514 136 32 32 0 0 normal + -1 sprites/openttdgui.png 8bpp 562 136 20 16 0 3 normal + -1 sprites/openttdgui.png 8bpp 594 136 56 43 0 0 normal + -1 sprites/openttdgui.png 8bpp 658 136 20 19 0 1 normal + -1 sprites/openttdgui.png 8bpp 690 136 32 32 0 0 normal + -1 sprites/openttdgui.png 8bpp 738 136 20 20 0 0 normal + -1 sprites/openttdgui.png 8bpp 2 200 31 31 1 1 normal + -1 sprites/openttdgui.png 8bpp 50 200 20 15 0 3 normal + -1 sprites/openttdgui.png 8bpp 82 200 56 36 0 0 normal + -1 sprites/openttdgui.png 8bpp 146 200 20 20 0 0 normal + -1 sprites/openttdgui.png 8bpp 178 200 32 32 0 0 normal + -1 sprites/openttdgui.png 8bpp 226 200 20 20 0 0 normal + -1 sprites/openttdgui.png 8bpp 258 200 32 32 0 0 normal + -1 sprites/openttdgui.png 8bpp 306 200 19 11 0 6 normal + -1 sprites/openttdgui.png 8bpp 338 200 56 36 0 0 normal + -1 sprites/openttdgui.png 8bpp 402 200 20 20 0 0 normal + -1 sprites/openttdgui.png 8bpp 434 200 32 32 0 0 normal + -1 sprites/openttdgui.png 8bpp 482 200 20 20 0 0 normal + -1 sprites/openttdgui.png 8bpp 514 200 32 32 0 0 normal + -1 sprites/openttdgui.png 8bpp 562 200 20 20 0 0 normal + -1 sprites/openttdgui.png 8bpp 594 200 20 20 0 0 normal + -1 sprites/openttdgui.png 8bpp 626 200 52 32 0 0 normal + -1 sprites/openttdgui.png 8bpp 690 200 29 33 -27 -16 normal + -1 sprites/openttdgui.png 8bpp 738 200 35 39 -29 -29 normal + -1 sprites/openttdgui.png 8bpp 2 264 29 34 1 -17 normal + -1 sprites/openttdgui.png 8bpp 50 264 34 39 -3 -28 normal + -1 sprites/openttdgui.png 8bpp 98 264 20 13 0 4 normal + -1 sprites/openttdgui.png 8bpp 130 264 56 36 0 0 normal + -1 sprites/openttdgui.png 8bpp 194 264 20 13 0 4 normal + -1 sprites/openttdgui.png 8bpp 226 264 56 36 0 0 normal + -1 sprites/openttdgui.png 8bpp 290 264 39 18 -9 -9 normal + -1 sprites/openttdgui.png 8bpp 338 264 72 44 -16 -35 normal + -1 sprites/openttdgui.png 8bpp 418 264 20 20 0 0 normal + -1 sprites/openttdgui.png 8bpp 450 264 72 44 -16 -35 normal + -1 sprites/openttdgui.png 8bpp 530 264 18 18 1 1 normal + -1 sprites/openttdgui.png 8bpp 562 264 20 20 0 0 normal + -1 sprites/openttdgui.png 8bpp 594 264 32 32 0 0 normal + -1 sprites/openttdgui.png 8bpp 642 264 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 674 264 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 706 264 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 738 264 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 770 264 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 2 328 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 34 328 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 66 328 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 98 328 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 130 328 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 162 328 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 194 328 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 226 328 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 258 328 16 16 0 0 normal + -1 sprites/openttdgui.png 8bpp 290 328 16 16 0 0 normal + -1 sprites/openttdgui.png 8bpp 322 328 16 16 0 0 normal + -1 sprites/openttdgui.png 8bpp 354 328 16 16 0 0 normal + -1 sprites/openttdgui.png 8bpp 386 328 35 31 0 0 normal + -1 sprites/openttdgui.png 8bpp 434 328 33 30 0 0 normal + -1 sprites/openttdgui.png 8bpp 482 328 36 33 0 0 normal + -1 sprites/openttdgui.png 8bpp 530 328 37 33 0 0 normal + -1 sprites/openttdgui.png 8bpp 578 328 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 610 328 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 642 328 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 674 328 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 706 328 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 738 328 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 770 328 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 2 376 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 34 376 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 66 376 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 98 376 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 130 376 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 162 376 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 194 376 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 226 376 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 258 376 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 290 376 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 322 376 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 354 376 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 386 376 18 18 0 0 normal + -1 sprites/openttdgui.png 8bpp 418 376 20 20 0 0 normal + -1 sprites/openttdgui.png 8bpp 450 376 19 22 0 0 normal + -1 sprites/openttdgui.png 8bpp 482 376 20 20 0 0 normal + -1 sprites/openttdgui.png 8bpp 514 376 54 44 -16 -35 normal + -1 sprites/openttdgui.png 8bpp 578 376 7 7 3 4 normal + -1 sprites/openttdgui.png 8bpp 594 376 7 7 3 4 normal + -1 sprites/openttdgui.png 8bpp 610 376 10 9 2 3 normal + -1 sprites/openttdgui.png 8bpp 626 376 10 9 2 3 normal + -1 sprites/openttdgui.png 8bpp 642 376 11 7 2 1 normal + -1 sprites/openttdgui.png 8bpp 658 376 9 9 3 3 normal + -1 sprites/openttdgui.png 8bpp 674 376 20 20 0 0 normal + -1 sprites/openttdgui.png 8bpp 706 376 20 20 0 0 normal + -1 sprites/openttdgui.png 8bpp 738 376 32 32 0 0 normal + -1 sprites/openttdgui.png 8bpp 786 376 10 10 0 0 normal + -1 sprites/openttdgui.png 8bpp 2 440 10 10 0 0 normal + -1 sprites/openttdgui.png 8bpp 18 440 7 7 0 0 normal + -1 sprites/openttdgui.png 8bpp 34 440 14 13 4 4 normal + -1 sprites/openttdgui.png 8bpp 66 440 7 8 0 0 normal + -1 sprites/openttdgui.png 8bpp 82 440 7 8 0 0 normal + -1 sprites/openttdgui.png 8bpp 98 440 7 8 0 0 normal + -1 sprites/openttdgui.png 8bpp 114 440 8 8 0 0 normal + -1 sprites/openttdgui.png 8bpp 130 440 8 8 0 0 normal + -1 sprites/openttdgui.png 8bpp 146 440 8 8 0 0 normal + -1 sprites/openttdgui.png 8bpp 162 440 8 8 0 0 normal + -1 sprites/openttdgui.png 8bpp 178 440 8 10 0 0 normal + -1 sprites/openttdgui.png 8bpp 194 440 13 10 0 -2 normal + -1 sprites/openttdgui.png 8bpp 215 440 9 10 0 0 normal + -1 sprites/openttdgui.png 8bpp 232 440 8 10 0 0 normal + -1 sprites/openttdgui.png 8bpp 248 440 8 8 0 0 normal + -1 sprites/openttdgui.png 8bpp 264 440 8 8 0 0 normal + -1 sprites/openttdgui.png 8bpp 280 440 8 8 0 0 normal + -1 sprites/openttdgui.png 8bpp 296 440 8 8 0 0 normal + -1 sprites/openttdgui.png 8bpp 312 440 14 10 0 0 normal + -1 sprites/openttdgui.png 8bpp 328 440 14 10 0 0 normal + -1 sprites/openttdgui.png 8bpp 348 440 8 8 0 0 normal + -1 sprites/openttdgui.png 8bpp 362 440 20 20 0 0 normal + -1 sprites/openttdgui.png 8bpp 388 440 20 20 0 0 normal + -1 sprites/openttdgui.png 8bpp 414 440 20 20 0 0 normal + -1 sprites/openttdgui.png 8bpp 440 440 20 20 0 0 normal + -1 sprites/openttdgui.png 8bpp 466 440 20 20 0 0 normal + -1 sprites/openttdgui.png 8bpp 490 440 20 20 0 0 normal diff --git a/media/extra_grf/openttdgui.png b/media/extra_grf/openttdgui.png new file mode 100644 index 0000000..28ad2fb Binary files /dev/null and b/media/extra_grf/openttdgui.png differ diff --git a/media/extra_grf/palette.nfo b/media/extra_grf/palette.nfo new file mode 100644 index 0000000..4a6ae69 --- /dev/null +++ b/media/extra_grf/palette.nfo @@ -0,0 +1,20 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// + + -1 * 0 0C "All black palette" + -1 * 0 05 18 01 + -1 * 0 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 01 diff --git a/media/extra_grf/rivers/arctic.nfo b/media/extra_grf/rivers/arctic.nfo new file mode 100644 index 0000000..646c9ed --- /dev/null +++ b/media/extra_grf/rivers/arctic.nfo @@ -0,0 +1,282 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// + -1 * 0 0C "Arctic river graphics by andythenorth (Andrew Parkhouse)" + -1 * 4 01 05 01 3C + -1 sprites/arctic_snowy.png 8bpp 10 10 38 19 -5 0 normal + -1 sprites/arctic_snowy.png 8bpp 58 10 38 18 -5 13 normal + -1 sprites/arctic_snowy.png 8bpp 106 10 38 18 -31 13 normal + -1 sprites/arctic_snowy.png 8bpp 154 10 38 19 -31 0 normal + -1 sprites/arctic_snowy.png 8bpp 202 10 19 9 14 11 normal + -1 sprites/arctic_snowy.png 8bpp 234 10 16 9 -7 22 normal + -1 sprites/arctic_snowy.png 8bpp 266 10 19 9 -31 11 normal + -1 sprites/arctic_snowy.png 8bpp 298 10 16 9 -7 0 normal + -1 sprites/arctic_snowy.png 8bpp 330 10 8 6 25 13 normal + -1 sprites/arctic_snowy.png 8bpp 346 10 12 4 -5 27 normal + -1 sprites/arctic_snowy.png 8bpp 364 10 8 6 -31 13 normal + -1 sprites/arctic_snowy.png 8bpp 380 10 12 5 -5 0 normal + + -1 sprites/arctic_snowy.png 8bpp 10 40 40 11 -7 0 normal + -1 sprites/arctic_snowy.png 8bpp 58 40 39 18 -6 5 normal + -1 sprites/arctic_snowy.png 8bpp 106 40 38 11 -31 12 normal + -1 sprites/arctic_snowy.png 8bpp 154 40 39 18 -31 0 normal + -1 sprites/arctic_snowy.png 8bpp 202 40 20 6 13 5 normal + -1 sprites/arctic_snowy.png 8bpp 234 40 13 7 -6 16 normal + -1 sprites/arctic_snowy.png 8bpp 266 40 20 6 -31 12 normal + -1 sprites/arctic_snowy.png 8bpp 298 40 13 7 -5 0 normal + -1 sprites/arctic_snowy.png 8bpp 330 40 8 5 25 6 normal + -1 sprites/arctic_snowy.png 8bpp 346 40 12 3 -5 20 normal + -1 sprites/arctic_snowy.png 8bpp 364 40 8 4 -31 13 normal + -1 sprites/arctic_snowy.png 8bpp 380 40 15 4 -7 0 normal + + -1 sprites/arctic_snowy.png 8bpp 10 70 38 20 -5 -8 normal + -1 sprites/arctic_snowy.png 8bpp 58 70 38 26 -5 5 normal + -1 sprites/arctic_snowy.png 8bpp 106 70 37 20 -31 11 normal + -1 sprites/arctic_snowy.png 8bpp 154 70 38 27 -31 -8 normal + -1 sprites/arctic_snowy.png 8bpp 202 70 16 9 17 3 normal + -1 sprites/arctic_snowy.png 8bpp 234 70 15 9 -7 22 normal + -1 sprites/arctic_snowy.png 8bpp 266 70 16 9 -31 11 normal + -1 sprites/arctic_snowy.png 8bpp 298 70 15 9 -6 -8 normal + -1 sprites/arctic_snowy.png 8bpp 330 70 8 7 25 5 normal + -1 sprites/arctic_snowy.png 8bpp 346 70 10 5 -4 27 normal + -1 sprites/arctic_snowy.png 8bpp 364 70 8 7 -31 11 normal + -1 sprites/arctic_snowy.png 8bpp 380 70 12 6 -5 -8 normal + + -1 sprites/arctic_snowy.png 8bpp 10 100 39 18 -6 0 normal + -1 sprites/arctic_snowy.png 8bpp 58 100 38 11 -5 12 normal + -1 sprites/arctic_snowy.png 8bpp 106 100 39 18 -31 5 normal + -1 sprites/arctic_snowy.png 8bpp 154 100 40 11 -32 0 normal + -1 sprites/arctic_snowy.png 8bpp 202 100 20 6 13 12 normal + -1 sprites/arctic_snowy.png 8bpp 234 100 13 7 -5 16 normal + -1 sprites/arctic_snowy.png 8bpp 266 100 20 6 -31 5 normal + -1 sprites/arctic_snowy.png 8bpp 298 100 13 7 -6 0 normal + -1 sprites/arctic_snowy.png 8bpp 330 100 8 4 26 13 normal + -1 sprites/arctic_snowy.png 8bpp 346 100 12 3 -5 20 normal + -1 sprites/arctic_snowy.png 8bpp 364 100 8 5 -31 6 normal + -1 sprites/arctic_snowy.png 8bpp 380 100 15 4 -6 0 normal + + -1 sprites/arctic_snowy.png 8bpp 10 130 38 27 -5 -8 normal + -1 sprites/arctic_snowy.png 8bpp 58 130 37 20 -4 11 normal + -1 sprites/arctic_snowy.png 8bpp 106 130 37 26 -31 5 normal + -1 sprites/arctic_snowy.png 8bpp 154 130 38 20 -31 -8 normal + -1 sprites/arctic_snowy.png 8bpp 202 130 16 9 17 11 normal + -1 sprites/arctic_snowy.png 8bpp 234 130 15 9 -6 22 normal + -1 sprites/arctic_snowy.png 8bpp 266 130 16 9 -31 3 normal + -1 sprites/arctic_snowy.png 8bpp 298 130 15 9 -7 -8 normal + -1 sprites/arctic_snowy.png 8bpp 330 130 8 7 25 11 normal + -1 sprites/arctic_snowy.png 8bpp 346 130 10 5 -4 26 normal + -1 sprites/arctic_snowy.png 8bpp 364 130 8 7 -31 5 normal + -1 sprites/arctic_snowy.png 8bpp 380 130 12 6 -5 -8 normal + -1 * 7 02 05 30 01 00 00 00 + + -1 * 4 01 05 01 3C + -1 sprites/arctic_brown.png 8bpp 10 10 38 19 -5 0 normal + -1 sprites/arctic_brown.png 8bpp 58 10 38 18 -5 13 normal + -1 sprites/arctic_brown.png 8bpp 106 10 38 18 -31 13 normal + -1 sprites/arctic_brown.png 8bpp 154 10 38 19 -31 0 normal + -1 sprites/arctic_brown.png 8bpp 202 10 19 9 14 11 normal + -1 sprites/arctic_brown.png 8bpp 234 10 16 9 -7 22 normal + -1 sprites/arctic_brown.png 8bpp 266 10 19 9 -31 11 normal + -1 sprites/arctic_brown.png 8bpp 298 10 16 9 -7 0 normal + -1 sprites/arctic_brown.png 8bpp 330 10 8 6 25 13 normal + -1 sprites/arctic_brown.png 8bpp 346 10 12 4 -5 27 normal + -1 sprites/arctic_brown.png 8bpp 364 10 8 6 -31 13 normal + -1 sprites/arctic_brown.png 8bpp 380 10 12 5 -5 0 normal + + -1 sprites/arctic_brown.png 8bpp 10 40 40 11 -7 0 normal + -1 sprites/arctic_brown.png 8bpp 58 40 39 18 -6 5 normal + -1 sprites/arctic_brown.png 8bpp 106 40 38 11 -31 12 normal + -1 sprites/arctic_brown.png 8bpp 154 40 39 18 -31 0 normal + -1 sprites/arctic_brown.png 8bpp 202 40 20 6 13 5 normal + -1 sprites/arctic_brown.png 8bpp 234 40 13 7 -6 16 normal + -1 sprites/arctic_brown.png 8bpp 266 40 20 6 -31 12 normal + -1 sprites/arctic_brown.png 8bpp 298 40 13 7 -5 0 normal + -1 sprites/arctic_brown.png 8bpp 330 40 8 5 25 6 normal + -1 sprites/arctic_brown.png 8bpp 346 40 12 3 -5 20 normal + -1 sprites/arctic_brown.png 8bpp 364 40 8 4 -31 13 normal + -1 sprites/arctic_brown.png 8bpp 380 40 15 4 -7 0 normal + + -1 sprites/arctic_brown.png 8bpp 10 70 38 20 -5 -8 normal + -1 sprites/arctic_brown.png 8bpp 58 70 38 26 -5 5 normal + -1 sprites/arctic_brown.png 8bpp 106 70 37 20 -31 11 normal + -1 sprites/arctic_brown.png 8bpp 154 70 38 27 -31 -8 normal + -1 sprites/arctic_brown.png 8bpp 202 70 16 9 17 3 normal + -1 sprites/arctic_brown.png 8bpp 234 70 15 9 -7 22 normal + -1 sprites/arctic_brown.png 8bpp 266 70 16 9 -31 11 normal + -1 sprites/arctic_brown.png 8bpp 298 70 15 9 -6 -8 normal + -1 sprites/arctic_brown.png 8bpp 330 70 8 7 25 5 normal + -1 sprites/arctic_brown.png 8bpp 346 70 10 5 -4 27 normal + -1 sprites/arctic_brown.png 8bpp 364 70 8 7 -31 11 normal + -1 sprites/arctic_brown.png 8bpp 380 70 12 6 -5 -8 normal + + -1 sprites/arctic_brown.png 8bpp 10 100 39 18 -6 0 normal + -1 sprites/arctic_brown.png 8bpp 58 100 38 11 -5 12 normal + -1 sprites/arctic_brown.png 8bpp 106 100 39 18 -31 5 normal + -1 sprites/arctic_brown.png 8bpp 154 100 40 11 -32 0 normal + -1 sprites/arctic_brown.png 8bpp 202 100 20 6 13 12 normal + -1 sprites/arctic_brown.png 8bpp 234 100 13 7 -5 16 normal + -1 sprites/arctic_brown.png 8bpp 266 100 20 6 -31 5 normal + -1 sprites/arctic_brown.png 8bpp 298 100 13 7 -6 0 normal + -1 sprites/arctic_brown.png 8bpp 330 100 8 4 26 13 normal + -1 sprites/arctic_brown.png 8bpp 346 100 12 3 -5 20 normal + -1 sprites/arctic_brown.png 8bpp 364 100 8 5 -31 6 normal + -1 sprites/arctic_brown.png 8bpp 380 100 15 4 -6 0 normal + + -1 sprites/arctic_brown.png 8bpp 10 130 38 27 -5 -8 normal + -1 sprites/arctic_brown.png 8bpp 58 130 37 20 -4 11 normal + -1 sprites/arctic_brown.png 8bpp 106 130 37 26 -31 5 normal + -1 sprites/arctic_brown.png 8bpp 154 130 38 20 -31 -8 normal + -1 sprites/arctic_brown.png 8bpp 202 130 16 9 17 11 normal + -1 sprites/arctic_brown.png 8bpp 234 130 15 9 -6 22 normal + -1 sprites/arctic_brown.png 8bpp 266 130 16 9 -31 3 normal + -1 sprites/arctic_brown.png 8bpp 298 130 15 9 -7 -8 normal + -1 sprites/arctic_brown.png 8bpp 330 130 8 7 25 11 normal + -1 sprites/arctic_brown.png 8bpp 346 130 10 5 -4 26 normal + -1 sprites/arctic_brown.png 8bpp 364 130 8 7 -31 5 normal + -1 sprites/arctic_brown.png 8bpp 380 130 12 6 -5 -8 normal + -1 * 7 02 05 31 01 00 00 00 + + -1 * 4 01 05 01 3C + -1 sprites/arctic_snowy.png 8bpp 10 210 38 19 -5 0 normal + -1 sprites/arctic_snowy.png 8bpp 58 210 38 18 -5 13 normal + -1 sprites/arctic_snowy.png 8bpp 106 210 38 18 -31 13 normal + -1 sprites/arctic_snowy.png 8bpp 154 210 38 19 -31 0 normal + -1 sprites/arctic_snowy.png 8bpp 202 210 19 9 14 11 normal + -1 sprites/arctic_snowy.png 8bpp 234 210 16 9 -7 22 normal + -1 sprites/arctic_snowy.png 8bpp 266 210 19 9 -31 11 normal + -1 sprites/arctic_snowy.png 8bpp 298 210 16 9 -7 0 normal + -1 sprites/arctic_snowy.png 8bpp 330 210 8 6 25 13 normal + -1 sprites/arctic_snowy.png 8bpp 346 210 12 4 -5 27 normal + -1 sprites/arctic_snowy.png 8bpp 364 210 8 6 -31 13 normal + -1 sprites/arctic_snowy.png 8bpp 380 210 12 5 -5 0 normal + + -1 sprites/arctic_snowy.png 8bpp 10 240 40 11 -7 0 normal + -1 sprites/arctic_snowy.png 8bpp 58 240 39 18 -6 5 normal + -1 sprites/arctic_snowy.png 8bpp 106 240 38 11 -31 12 normal + -1 sprites/arctic_snowy.png 8bpp 154 240 39 18 -31 0 normal + -1 sprites/arctic_snowy.png 8bpp 202 240 20 6 13 5 normal + -1 sprites/arctic_snowy.png 8bpp 234 240 13 7 -6 16 normal + -1 sprites/arctic_snowy.png 8bpp 266 240 20 6 -31 12 normal + -1 sprites/arctic_snowy.png 8bpp 298 240 13 7 -5 0 normal + -1 sprites/arctic_snowy.png 8bpp 330 240 8 5 25 6 normal + -1 sprites/arctic_snowy.png 8bpp 346 240 12 3 -5 20 normal + -1 sprites/arctic_snowy.png 8bpp 364 240 8 4 -31 13 normal + -1 sprites/arctic_snowy.png 8bpp 380 240 15 4 -7 0 normal + + -1 sprites/arctic_snowy.png 8bpp 10 270 38 20 -5 -8 normal + -1 sprites/arctic_snowy.png 8bpp 58 270 38 26 -5 5 normal + -1 sprites/arctic_snowy.png 8bpp 106 270 37 20 -31 11 normal + -1 sprites/arctic_snowy.png 8bpp 154 270 38 27 -31 -8 normal + -1 sprites/arctic_snowy.png 8bpp 202 270 16 9 17 3 normal + -1 sprites/arctic_snowy.png 8bpp 234 270 15 9 -7 22 normal + -1 sprites/arctic_snowy.png 8bpp 266 270 16 9 -31 11 normal + -1 sprites/arctic_snowy.png 8bpp 298 270 15 9 -6 -8 normal + -1 sprites/arctic_snowy.png 8bpp 330 270 8 7 25 5 normal + -1 sprites/arctic_snowy.png 8bpp 346 270 10 5 -4 27 normal + -1 sprites/arctic_snowy.png 8bpp 364 270 8 7 -31 11 normal + -1 sprites/arctic_snowy.png 8bpp 380 270 12 6 -5 -8 normal + + -1 sprites/arctic_snowy.png 8bpp 10 300 39 18 -6 0 normal + -1 sprites/arctic_snowy.png 8bpp 58 300 38 11 -5 12 normal + -1 sprites/arctic_snowy.png 8bpp 106 300 39 18 -31 5 normal + -1 sprites/arctic_snowy.png 8bpp 154 300 40 11 -32 0 normal + -1 sprites/arctic_snowy.png 8bpp 202 300 20 6 13 12 normal + -1 sprites/arctic_snowy.png 8bpp 234 300 13 7 -5 16 normal + -1 sprites/arctic_snowy.png 8bpp 266 300 20 6 -31 5 normal + -1 sprites/arctic_snowy.png 8bpp 298 300 13 7 -6 0 normal + -1 sprites/arctic_snowy.png 8bpp 330 300 8 4 26 13 normal + -1 sprites/arctic_snowy.png 8bpp 346 300 12 3 -5 20 normal + -1 sprites/arctic_snowy.png 8bpp 364 300 8 5 -31 6 normal + -1 sprites/arctic_snowy.png 8bpp 380 300 15 4 -6 0 normal + + -1 sprites/arctic_snowy.png 8bpp 10 330 38 27 -5 -8 normal + -1 sprites/arctic_snowy.png 8bpp 58 330 37 20 -4 11 normal + -1 sprites/arctic_snowy.png 8bpp 106 330 37 26 -31 5 normal + -1 sprites/arctic_snowy.png 8bpp 154 330 38 20 -31 -8 normal + -1 sprites/arctic_snowy.png 8bpp 202 330 16 9 17 11 normal + -1 sprites/arctic_snowy.png 8bpp 234 330 15 9 -6 22 normal + -1 sprites/arctic_snowy.png 8bpp 266 330 16 9 -31 3 normal + -1 sprites/arctic_snowy.png 8bpp 298 330 15 9 -7 -8 normal + -1 sprites/arctic_snowy.png 8bpp 330 330 8 7 25 11 normal + -1 sprites/arctic_snowy.png 8bpp 346 330 10 5 -4 26 normal + -1 sprites/arctic_snowy.png 8bpp 364 330 8 7 -31 5 normal + -1 sprites/arctic_snowy.png 8bpp 380 330 12 6 -5 -8 normal + -1 * 7 02 05 32 01 00 00 00 + + -1 * 4 01 05 01 3C + -1 sprites/arctic_brown.png 8bpp 10 210 38 19 -5 0 normal + -1 sprites/arctic_brown.png 8bpp 58 210 38 18 -5 13 normal + -1 sprites/arctic_brown.png 8bpp 106 210 38 18 -31 13 normal + -1 sprites/arctic_brown.png 8bpp 154 210 38 19 -31 0 normal + -1 sprites/arctic_brown.png 8bpp 202 210 19 9 14 11 normal + -1 sprites/arctic_brown.png 8bpp 234 210 16 9 -7 22 normal + -1 sprites/arctic_brown.png 8bpp 266 210 19 9 -31 11 normal + -1 sprites/arctic_brown.png 8bpp 298 210 16 9 -7 0 normal + -1 sprites/arctic_brown.png 8bpp 330 210 8 6 25 13 normal + -1 sprites/arctic_brown.png 8bpp 346 210 12 4 -5 27 normal + -1 sprites/arctic_brown.png 8bpp 364 210 8 6 -31 13 normal + -1 sprites/arctic_brown.png 8bpp 380 210 12 5 -5 0 normal + + -1 sprites/arctic_brown.png 8bpp 10 240 40 11 -7 0 normal + -1 sprites/arctic_brown.png 8bpp 58 240 39 18 -6 5 normal + -1 sprites/arctic_brown.png 8bpp 106 240 38 11 -31 12 normal + -1 sprites/arctic_brown.png 8bpp 154 240 39 18 -31 0 normal + -1 sprites/arctic_brown.png 8bpp 202 240 20 6 13 5 normal + -1 sprites/arctic_brown.png 8bpp 234 240 13 7 -6 16 normal + -1 sprites/arctic_brown.png 8bpp 266 240 20 6 -31 12 normal + -1 sprites/arctic_brown.png 8bpp 298 240 13 7 -5 0 normal + -1 sprites/arctic_brown.png 8bpp 330 240 8 5 25 6 normal + -1 sprites/arctic_brown.png 8bpp 346 240 12 3 -5 20 normal + -1 sprites/arctic_brown.png 8bpp 364 240 8 4 -31 13 normal + -1 sprites/arctic_brown.png 8bpp 380 240 15 4 -7 0 normal + + -1 sprites/arctic_brown.png 8bpp 10 270 38 20 -5 -8 normal + -1 sprites/arctic_brown.png 8bpp 58 270 38 26 -5 5 normal + -1 sprites/arctic_brown.png 8bpp 106 270 37 20 -31 11 normal + -1 sprites/arctic_brown.png 8bpp 154 270 38 27 -31 -8 normal + -1 sprites/arctic_brown.png 8bpp 202 270 16 9 17 3 normal + -1 sprites/arctic_brown.png 8bpp 234 270 15 9 -7 22 normal + -1 sprites/arctic_brown.png 8bpp 266 270 16 9 -31 11 normal + -1 sprites/arctic_brown.png 8bpp 298 270 15 9 -6 -8 normal + -1 sprites/arctic_brown.png 8bpp 330 270 8 7 25 5 normal + -1 sprites/arctic_brown.png 8bpp 346 270 10 5 -4 27 normal + -1 sprites/arctic_brown.png 8bpp 364 270 8 7 -31 11 normal + -1 sprites/arctic_brown.png 8bpp 380 270 12 6 -5 -8 normal + + -1 sprites/arctic_brown.png 8bpp 10 300 39 18 -6 0 normal + -1 sprites/arctic_brown.png 8bpp 58 300 38 11 -5 12 normal + -1 sprites/arctic_brown.png 8bpp 106 300 39 18 -31 5 normal + -1 sprites/arctic_brown.png 8bpp 154 300 40 11 -32 0 normal + -1 sprites/arctic_brown.png 8bpp 202 300 20 6 13 12 normal + -1 sprites/arctic_brown.png 8bpp 234 300 13 7 -5 16 normal + -1 sprites/arctic_brown.png 8bpp 266 300 20 6 -31 5 normal + -1 sprites/arctic_brown.png 8bpp 298 300 13 7 -6 0 normal + -1 sprites/arctic_brown.png 8bpp 330 300 8 4 26 13 normal + -1 sprites/arctic_brown.png 8bpp 346 300 12 3 -5 20 normal + -1 sprites/arctic_brown.png 8bpp 364 300 8 5 -31 6 normal + -1 sprites/arctic_brown.png 8bpp 380 300 15 4 -6 0 normal + + -1 sprites/arctic_brown.png 8bpp 10 330 38 27 -5 -8 normal + -1 sprites/arctic_brown.png 8bpp 58 330 37 20 -4 11 normal + -1 sprites/arctic_brown.png 8bpp 106 330 37 26 -31 5 normal + -1 sprites/arctic_brown.png 8bpp 154 330 38 20 -31 -8 normal + -1 sprites/arctic_brown.png 8bpp 202 330 16 9 17 11 normal + -1 sprites/arctic_brown.png 8bpp 234 330 15 9 -6 22 normal + -1 sprites/arctic_brown.png 8bpp 266 330 16 9 -31 3 normal + -1 sprites/arctic_brown.png 8bpp 298 330 15 9 -7 -8 normal + -1 sprites/arctic_brown.png 8bpp 330 330 8 7 25 11 normal + -1 sprites/arctic_brown.png 8bpp 346 330 10 5 -4 26 normal + -1 sprites/arctic_brown.png 8bpp 364 330 8 7 -31 5 normal + -1 sprites/arctic_brown.png 8bpp 380 330 12 6 -5 -8 normal + -1 * 7 02 05 33 01 00 00 00 + + -1 * 14 02 05 34 81 81 00 FF 01 30 00 04 04 31 00 + -1 * 14 02 05 35 81 81 00 FF 01 32 00 04 04 33 00 + -1 * 14 02 05 36 81 80 00 FF 01 34 00 00 00 35 00 + -1 * 6 07 83 01 \7! 01 01 + -1 * 7 03 05 01 06 00 36 00 diff --git a/media/extra_grf/rivers/arctic_brown.png b/media/extra_grf/rivers/arctic_brown.png new file mode 100644 index 0000000..c2a6c94 Binary files /dev/null and b/media/extra_grf/rivers/arctic_brown.png differ diff --git a/media/extra_grf/rivers/arctic_snowy.png b/media/extra_grf/rivers/arctic_snowy.png new file mode 100644 index 0000000..5e44e76 Binary files /dev/null and b/media/extra_grf/rivers/arctic_snowy.png differ diff --git a/media/extra_grf/rivers/rapids.nfo b/media/extra_grf/rivers/rapids.nfo new file mode 100644 index 0000000..f66f3dc --- /dev/null +++ b/media/extra_grf/rivers/rapids.nfo @@ -0,0 +1,139 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// + -1 * 0 0C "Rapid graphics" + -1 * 4 01 05 01 04 + -1 sprites/rapids.png 8bpp 10 10 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 90 10 64 39 -31 -8 normal + -1 sprites/rapids.png 8bpp 170 10 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 250 10 64 39 -31 -8 normal + -1 * 7 02 05 00 01 00 00 00 + + -1 * 4 01 05 01 04 + -1 sprites/rapids.png 8bpp 10 60 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 90 60 64 39 -31 -8 normal + -1 sprites/rapids.png 8bpp 170 60 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 250 60 64 39 -31 -8 normal + -1 * 7 02 05 01 01 00 00 00 + + -1 * 4 01 05 01 04 + -1 sprites/rapids.png 8bpp 10 110 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 90 110 64 39 -31 -8 normal + -1 sprites/rapids.png 8bpp 170 110 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 250 110 64 39 -31 -8 normal + -1 * 7 02 05 02 01 00 00 00 + + -1 * 4 01 05 01 04 + -1 sprites/rapids.png 8bpp 10 160 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 90 160 64 39 -31 -8 normal + -1 sprites/rapids.png 8bpp 170 160 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 250 160 64 39 -31 -8 normal + -1 * 7 02 05 03 01 00 00 00 + + -1 * 4 01 05 01 04 + -1 sprites/rapids.png 8bpp 10 210 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 90 210 64 39 -31 -8 normal + -1 sprites/rapids.png 8bpp 170 210 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 250 210 64 39 -31 -8 normal + -1 * 7 02 05 04 01 00 00 00 + + -1 * 4 01 05 01 04 + -1 sprites/rapids.png 8bpp 10 260 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 90 260 64 39 -31 -8 normal + -1 sprites/rapids.png 8bpp 170 260 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 250 260 64 39 -31 -8 normal + -1 * 7 02 05 05 01 00 00 00 + + -1 * 4 01 05 01 04 + -1 sprites/rapids.png 8bpp 10 310 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 90 310 64 39 -31 -8 normal + -1 sprites/rapids.png 8bpp 170 310 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 250 310 64 39 -31 -8 normal + -1 * 7 02 05 06 01 00 00 00 + + -1 * 4 01 05 01 04 + -1 sprites/rapids.png 8bpp 10 360 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 90 360 64 39 -31 -8 normal + -1 sprites/rapids.png 8bpp 170 360 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 250 360 64 39 -31 -8 normal + -1 * 7 02 05 07 01 00 00 00 + + -1 * 4 01 05 01 04 + -1 sprites/rapids.png 8bpp 10 410 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 90 410 64 39 -31 -8 normal + -1 sprites/rapids.png 8bpp 170 410 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 250 410 64 39 -31 -8 normal + -1 * 7 02 05 08 01 00 00 00 + + -1 * 4 01 05 01 04 + -1 sprites/rapids.png 8bpp 10 460 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 90 460 64 39 -31 -8 normal + -1 sprites/rapids.png 8bpp 170 460 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 250 460 64 39 -31 -8 normal + -1 * 7 02 05 09 01 00 00 00 + + -1 * 4 01 05 01 04 + -1 sprites/rapids.png 8bpp 10 510 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 90 510 64 39 -31 -8 normal + -1 sprites/rapids.png 8bpp 170 510 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 250 510 64 39 -31 -8 normal + -1 * 7 02 05 0A 01 00 00 00 + + -1 * 4 01 05 01 04 + -1 sprites/rapids.png 8bpp 10 560 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 90 560 64 39 -31 -8 normal + -1 sprites/rapids.png 8bpp 170 560 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 250 560 64 39 -31 -8 normal + -1 * 7 02 05 0B 01 00 00 00 + + -1 * 4 01 05 01 04 + -1 sprites/rapids.png 8bpp 10 610 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 90 610 64 39 -31 -8 normal + -1 sprites/rapids.png 8bpp 170 610 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 250 610 64 39 -31 -8 normal + -1 * 7 02 05 0C 01 00 00 00 + + -1 * 4 01 05 01 04 + -1 sprites/rapids.png 8bpp 10 660 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 90 660 64 39 -31 -8 normal + -1 sprites/rapids.png 8bpp 170 660 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 250 660 64 39 -31 -8 normal + -1 * 7 02 05 0D 01 00 00 00 + + -1 * 4 01 05 01 04 + -1 sprites/rapids.png 8bpp 10 710 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 90 710 64 39 -31 -8 normal + -1 sprites/rapids.png 8bpp 170 710 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 250 710 64 39 -31 -8 normal + -1 * 7 02 05 0E 01 00 00 00 + + -1 * 4 01 05 01 04 + -1 sprites/rapids.png 8bpp 10 760 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 90 760 64 39 -31 -8 normal + -1 sprites/rapids.png 8bpp 170 760 64 23 -31 0 normal + -1 sprites/rapids.png 8bpp 250 760 64 39 -31 -8 normal + -1 * 7 02 05 0F 01 00 00 00 + + -1 * 39 02 05 10 80 00 01 10 + 00 00 + 01 00 + 02 00 + 03 00 + 04 00 + 05 00 + 06 00 + 07 00 + 08 00 + 09 00 + 0A 00 + 0B 00 + 0C 00 + 0D 00 + 0E 00 + 0F 00 + -1 * 7 03 05 01 05 00 10 00 diff --git a/media/extra_grf/rivers/rapids.png b/media/extra_grf/rivers/rapids.png new file mode 100644 index 0000000..db25ae0 Binary files /dev/null and b/media/extra_grf/rivers/rapids.png differ diff --git a/media/extra_grf/rivers/temperate.nfo b/media/extra_grf/rivers/temperate.nfo new file mode 100644 index 0000000..a5af841 --- /dev/null +++ b/media/extra_grf/rivers/temperate.nfo @@ -0,0 +1,146 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// + -1 * 0 0C "Temperate river graphics by andythenorth (Andrew Parkhouse)" + -1 * 4 01 05 01 3C + -1 sprites/temperate.png 8bpp 10 10 38 19 -5 0 normal + -1 sprites/temperate.png 8bpp 58 10 38 18 -5 13 normal + -1 sprites/temperate.png 8bpp 106 10 38 18 -31 13 normal + -1 sprites/temperate.png 8bpp 154 10 38 19 -31 0 normal + -1 sprites/temperate.png 8bpp 202 10 19 9 14 11 normal + -1 sprites/temperate.png 8bpp 234 10 16 9 -7 22 normal + -1 sprites/temperate.png 8bpp 266 10 19 9 -31 11 normal + -1 sprites/temperate.png 8bpp 298 10 16 9 -7 0 normal + -1 sprites/temperate.png 8bpp 330 10 8 6 25 13 normal + -1 sprites/temperate.png 8bpp 346 10 12 4 -5 27 normal + -1 sprites/temperate.png 8bpp 364 10 8 6 -31 13 normal + -1 sprites/temperate.png 8bpp 380 10 12 5 -5 0 normal + + -1 sprites/temperate.png 8bpp 10 40 40 11 -7 0 normal + -1 sprites/temperate.png 8bpp 58 40 39 18 -6 5 normal + -1 sprites/temperate.png 8bpp 106 40 38 11 -31 12 normal + -1 sprites/temperate.png 8bpp 154 40 39 18 -31 0 normal + -1 sprites/temperate.png 8bpp 202 40 20 6 13 5 normal + -1 sprites/temperate.png 8bpp 234 40 13 7 -6 16 normal + -1 sprites/temperate.png 8bpp 266 40 20 6 -31 12 normal + -1 sprites/temperate.png 8bpp 298 40 13 7 -5 0 normal + -1 sprites/temperate.png 8bpp 330 40 8 5 25 6 normal + -1 sprites/temperate.png 8bpp 346 40 12 3 -5 20 normal + -1 sprites/temperate.png 8bpp 364 40 8 4 -31 13 normal + -1 sprites/temperate.png 8bpp 380 40 15 4 -7 0 normal + + -1 sprites/temperate.png 8bpp 10 70 38 20 -5 -8 normal + -1 sprites/temperate.png 8bpp 58 70 38 26 -5 5 normal + -1 sprites/temperate.png 8bpp 106 70 37 20 -31 11 normal + -1 sprites/temperate.png 8bpp 154 70 38 27 -31 -8 normal + -1 sprites/temperate.png 8bpp 202 70 16 9 17 3 normal + -1 sprites/temperate.png 8bpp 234 70 15 9 -7 22 normal + -1 sprites/temperate.png 8bpp 266 70 16 9 -31 11 normal + -1 sprites/temperate.png 8bpp 298 70 15 9 -6 -8 normal + -1 sprites/temperate.png 8bpp 330 70 8 7 25 5 normal + -1 sprites/temperate.png 8bpp 346 70 10 5 -4 27 normal + -1 sprites/temperate.png 8bpp 364 70 8 7 -31 11 normal + -1 sprites/temperate.png 8bpp 380 70 12 6 -5 -8 normal + + -1 sprites/temperate.png 8bpp 10 100 39 18 -6 0 normal + -1 sprites/temperate.png 8bpp 58 100 38 11 -5 12 normal + -1 sprites/temperate.png 8bpp 106 100 39 18 -31 5 normal + -1 sprites/temperate.png 8bpp 154 100 40 11 -32 0 normal + -1 sprites/temperate.png 8bpp 202 100 20 6 13 12 normal + -1 sprites/temperate.png 8bpp 234 100 13 7 -5 16 normal + -1 sprites/temperate.png 8bpp 266 100 20 6 -31 5 normal + -1 sprites/temperate.png 8bpp 298 100 13 7 -6 0 normal + -1 sprites/temperate.png 8bpp 330 100 8 4 26 13 normal + -1 sprites/temperate.png 8bpp 346 100 12 3 -5 20 normal + -1 sprites/temperate.png 8bpp 364 100 8 5 -31 6 normal + -1 sprites/temperate.png 8bpp 380 100 15 4 -6 0 normal + + -1 sprites/temperate.png 8bpp 10 130 38 27 -5 -8 normal + -1 sprites/temperate.png 8bpp 58 130 37 20 -4 11 normal + -1 sprites/temperate.png 8bpp 106 130 37 26 -31 5 normal + -1 sprites/temperate.png 8bpp 154 130 38 20 -31 -8 normal + -1 sprites/temperate.png 8bpp 202 130 16 9 17 11 normal + -1 sprites/temperate.png 8bpp 234 130 15 9 -6 22 normal + -1 sprites/temperate.png 8bpp 266 130 16 9 -31 3 normal + -1 sprites/temperate.png 8bpp 298 130 15 9 -7 -8 normal + -1 sprites/temperate.png 8bpp 330 130 8 7 25 11 normal + -1 sprites/temperate.png 8bpp 346 130 10 5 -4 26 normal + -1 sprites/temperate.png 8bpp 364 130 8 7 -31 5 normal + -1 sprites/temperate.png 8bpp 380 130 12 6 -5 -8 normal + -1 * 7 02 05 20 01 00 00 00 + + -1 * 4 01 05 01 3C + -1 sprites/temperate.png 8bpp 10 210 38 19 -5 0 normal + -1 sprites/temperate.png 8bpp 58 210 38 18 -5 13 normal + -1 sprites/temperate.png 8bpp 106 210 38 18 -31 13 normal + -1 sprites/temperate.png 8bpp 154 210 38 19 -31 0 normal + -1 sprites/temperate.png 8bpp 202 210 19 9 14 11 normal + -1 sprites/temperate.png 8bpp 234 210 16 9 -7 22 normal + -1 sprites/temperate.png 8bpp 266 210 19 9 -31 11 normal + -1 sprites/temperate.png 8bpp 298 210 16 9 -7 0 normal + -1 sprites/temperate.png 8bpp 330 210 8 6 25 13 normal + -1 sprites/temperate.png 8bpp 346 210 12 4 -5 27 normal + -1 sprites/temperate.png 8bpp 364 210 8 6 -31 13 normal + -1 sprites/temperate.png 8bpp 380 210 12 5 -5 0 normal + + -1 sprites/temperate.png 8bpp 10 240 40 11 -7 0 normal + -1 sprites/temperate.png 8bpp 58 240 39 18 -6 5 normal + -1 sprites/temperate.png 8bpp 106 240 38 11 -31 12 normal + -1 sprites/temperate.png 8bpp 154 240 39 18 -31 0 normal + -1 sprites/temperate.png 8bpp 202 240 20 6 13 5 normal + -1 sprites/temperate.png 8bpp 234 240 13 7 -6 16 normal + -1 sprites/temperate.png 8bpp 266 240 20 6 -31 12 normal + -1 sprites/temperate.png 8bpp 298 240 13 7 -5 0 normal + -1 sprites/temperate.png 8bpp 330 240 8 5 25 6 normal + -1 sprites/temperate.png 8bpp 346 240 12 3 -5 20 normal + -1 sprites/temperate.png 8bpp 364 240 8 4 -31 13 normal + -1 sprites/temperate.png 8bpp 380 240 15 4 -7 0 normal + + -1 sprites/temperate.png 8bpp 10 270 38 20 -5 -8 normal + -1 sprites/temperate.png 8bpp 58 270 38 26 -5 5 normal + -1 sprites/temperate.png 8bpp 106 270 37 20 -31 11 normal + -1 sprites/temperate.png 8bpp 154 270 38 27 -31 -8 normal + -1 sprites/temperate.png 8bpp 202 270 16 9 17 3 normal + -1 sprites/temperate.png 8bpp 234 270 15 9 -7 22 normal + -1 sprites/temperate.png 8bpp 266 270 16 9 -31 11 normal + -1 sprites/temperate.png 8bpp 298 270 15 9 -6 -8 normal + -1 sprites/temperate.png 8bpp 330 270 8 7 25 5 normal + -1 sprites/temperate.png 8bpp 346 270 10 5 -4 27 normal + -1 sprites/temperate.png 8bpp 364 270 8 7 -31 11 normal + -1 sprites/temperate.png 8bpp 380 270 12 6 -5 -8 normal + + -1 sprites/temperate.png 8bpp 10 300 39 18 -6 0 normal + -1 sprites/temperate.png 8bpp 58 300 38 11 -5 12 normal + -1 sprites/temperate.png 8bpp 106 300 39 18 -31 5 normal + -1 sprites/temperate.png 8bpp 154 300 40 11 -32 0 normal + -1 sprites/temperate.png 8bpp 202 300 20 6 13 12 normal + -1 sprites/temperate.png 8bpp 234 300 13 7 -5 16 normal + -1 sprites/temperate.png 8bpp 266 300 20 6 -31 5 normal + -1 sprites/temperate.png 8bpp 298 300 13 7 -6 0 normal + -1 sprites/temperate.png 8bpp 330 300 8 4 26 13 normal + -1 sprites/temperate.png 8bpp 346 300 12 3 -5 20 normal + -1 sprites/temperate.png 8bpp 364 300 8 5 -31 6 normal + -1 sprites/temperate.png 8bpp 380 300 15 4 -6 0 normal + + -1 sprites/temperate.png 8bpp 10 330 38 27 -5 -8 normal + -1 sprites/temperate.png 8bpp 58 330 37 20 -4 11 normal + -1 sprites/temperate.png 8bpp 106 330 37 26 -31 5 normal + -1 sprites/temperate.png 8bpp 154 330 38 20 -31 -8 normal + -1 sprites/temperate.png 8bpp 202 330 16 9 17 11 normal + -1 sprites/temperate.png 8bpp 234 330 15 9 -6 22 normal + -1 sprites/temperate.png 8bpp 266 330 16 9 -31 3 normal + -1 sprites/temperate.png 8bpp 298 330 15 9 -7 -8 normal + -1 sprites/temperate.png 8bpp 330 330 8 7 25 11 normal + -1 sprites/temperate.png 8bpp 346 330 10 5 -4 26 normal + -1 sprites/temperate.png 8bpp 364 330 8 7 -31 5 normal + -1 sprites/temperate.png 8bpp 380 330 12 6 -5 -8 normal + -1 * 7 02 05 21 01 00 00 00 + + -1 * 14 02 05 22 81 80 00 FF 01 20 00 00 00 21 00 + -1 * 6 07 83 01 \7! 00 01 + -1 * 7 03 05 01 06 00 22 00 diff --git a/media/extra_grf/rivers/temperate.png b/media/extra_grf/rivers/temperate.png new file mode 100644 index 0000000..61ff224 Binary files /dev/null and b/media/extra_grf/rivers/temperate.png differ diff --git a/media/extra_grf/rivers/toyland.nfo b/media/extra_grf/rivers/toyland.nfo new file mode 100644 index 0000000..ca65ce1 --- /dev/null +++ b/media/extra_grf/rivers/toyland.nfo @@ -0,0 +1,146 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// + -1 * 0 0C "Toyland river graphics by andythenorth (Andrew Parkhouse)" + -1 * 4 01 05 01 3C + -1 sprites/toyland.png 8bpp 10 10 38 19 -5 0 normal + -1 sprites/toyland.png 8bpp 58 10 38 18 -5 13 normal + -1 sprites/toyland.png 8bpp 106 10 38 18 -31 13 normal + -1 sprites/toyland.png 8bpp 154 10 38 19 -31 0 normal + -1 sprites/toyland.png 8bpp 202 10 19 9 14 11 normal + -1 sprites/toyland.png 8bpp 234 10 16 9 -7 22 normal + -1 sprites/toyland.png 8bpp 266 10 19 9 -31 11 normal + -1 sprites/toyland.png 8bpp 298 10 16 9 -7 0 normal + -1 sprites/toyland.png 8bpp 330 10 8 6 25 13 normal + -1 sprites/toyland.png 8bpp 346 10 12 4 -5 27 normal + -1 sprites/toyland.png 8bpp 364 10 8 6 -31 13 normal + -1 sprites/toyland.png 8bpp 380 10 12 5 -5 0 normal + + -1 sprites/toyland.png 8bpp 10 40 40 11 -7 0 normal + -1 sprites/toyland.png 8bpp 58 40 39 18 -6 5 normal + -1 sprites/toyland.png 8bpp 106 40 38 11 -31 12 normal + -1 sprites/toyland.png 8bpp 154 40 39 18 -31 0 normal + -1 sprites/toyland.png 8bpp 202 40 20 6 13 5 normal + -1 sprites/toyland.png 8bpp 234 40 13 7 -6 16 normal + -1 sprites/toyland.png 8bpp 266 40 20 6 -31 12 normal + -1 sprites/toyland.png 8bpp 298 40 13 7 -5 0 normal + -1 sprites/toyland.png 8bpp 330 40 8 5 25 6 normal + -1 sprites/toyland.png 8bpp 346 40 12 3 -5 20 normal + -1 sprites/toyland.png 8bpp 364 40 8 4 -31 13 normal + -1 sprites/toyland.png 8bpp 380 40 15 4 -7 0 normal + + -1 sprites/toyland.png 8bpp 10 70 38 20 -5 -8 normal + -1 sprites/toyland.png 8bpp 58 70 38 26 -5 5 normal + -1 sprites/toyland.png 8bpp 106 70 37 20 -31 11 normal + -1 sprites/toyland.png 8bpp 154 70 38 27 -31 -8 normal + -1 sprites/toyland.png 8bpp 202 70 16 9 17 3 normal + -1 sprites/toyland.png 8bpp 234 70 15 9 -7 22 normal + -1 sprites/toyland.png 8bpp 266 70 16 9 -31 11 normal + -1 sprites/toyland.png 8bpp 298 70 15 9 -6 -8 normal + -1 sprites/toyland.png 8bpp 330 70 8 7 25 5 normal + -1 sprites/toyland.png 8bpp 346 70 10 5 -4 27 normal + -1 sprites/toyland.png 8bpp 364 70 8 7 -31 11 normal + -1 sprites/toyland.png 8bpp 380 70 12 6 -5 -8 normal + + -1 sprites/toyland.png 8bpp 10 100 39 18 -6 0 normal + -1 sprites/toyland.png 8bpp 58 100 38 11 -5 12 normal + -1 sprites/toyland.png 8bpp 106 100 39 18 -31 5 normal + -1 sprites/toyland.png 8bpp 154 100 40 11 -32 0 normal + -1 sprites/toyland.png 8bpp 202 100 20 6 13 12 normal + -1 sprites/toyland.png 8bpp 234 100 13 7 -5 16 normal + -1 sprites/toyland.png 8bpp 266 100 20 6 -31 5 normal + -1 sprites/toyland.png 8bpp 298 100 13 7 -6 0 normal + -1 sprites/toyland.png 8bpp 330 100 8 4 26 13 normal + -1 sprites/toyland.png 8bpp 346 100 12 3 -5 20 normal + -1 sprites/toyland.png 8bpp 364 100 8 5 -31 6 normal + -1 sprites/toyland.png 8bpp 380 100 15 4 -6 0 normal + + -1 sprites/toyland.png 8bpp 10 130 38 27 -5 -8 normal + -1 sprites/toyland.png 8bpp 58 130 37 20 -4 11 normal + -1 sprites/toyland.png 8bpp 106 130 37 26 -31 5 normal + -1 sprites/toyland.png 8bpp 154 130 38 20 -31 -8 normal + -1 sprites/toyland.png 8bpp 202 130 16 9 17 11 normal + -1 sprites/toyland.png 8bpp 234 130 15 9 -6 22 normal + -1 sprites/toyland.png 8bpp 266 130 16 9 -31 3 normal + -1 sprites/toyland.png 8bpp 298 130 15 9 -7 -8 normal + -1 sprites/toyland.png 8bpp 330 130 8 7 25 11 normal + -1 sprites/toyland.png 8bpp 346 130 10 5 -4 26 normal + -1 sprites/toyland.png 8bpp 364 130 8 7 -31 5 normal + -1 sprites/toyland.png 8bpp 380 130 12 6 -5 -8 normal + -1 * 7 02 05 50 01 00 00 00 + + -1 * 4 01 05 01 3C + -1 sprites/toyland.png 8bpp 10 210 38 19 -5 0 normal + -1 sprites/toyland.png 8bpp 58 210 38 18 -5 13 normal + -1 sprites/toyland.png 8bpp 106 210 38 18 -31 13 normal + -1 sprites/toyland.png 8bpp 154 210 38 19 -31 0 normal + -1 sprites/toyland.png 8bpp 202 210 19 9 14 11 normal + -1 sprites/toyland.png 8bpp 234 210 16 9 -7 22 normal + -1 sprites/toyland.png 8bpp 266 210 19 9 -31 11 normal + -1 sprites/toyland.png 8bpp 298 210 16 9 -7 0 normal + -1 sprites/toyland.png 8bpp 330 210 8 6 25 13 normal + -1 sprites/toyland.png 8bpp 346 210 12 4 -5 27 normal + -1 sprites/toyland.png 8bpp 364 210 8 6 -31 13 normal + -1 sprites/toyland.png 8bpp 380 210 12 5 -5 0 normal + + -1 sprites/toyland.png 8bpp 10 240 40 11 -7 0 normal + -1 sprites/toyland.png 8bpp 58 240 39 18 -6 5 normal + -1 sprites/toyland.png 8bpp 106 240 38 11 -31 12 normal + -1 sprites/toyland.png 8bpp 154 240 39 18 -31 0 normal + -1 sprites/toyland.png 8bpp 202 240 20 6 13 5 normal + -1 sprites/toyland.png 8bpp 234 240 13 7 -6 16 normal + -1 sprites/toyland.png 8bpp 266 240 20 6 -31 12 normal + -1 sprites/toyland.png 8bpp 298 240 13 7 -5 0 normal + -1 sprites/toyland.png 8bpp 330 240 8 5 25 6 normal + -1 sprites/toyland.png 8bpp 346 240 12 3 -5 20 normal + -1 sprites/toyland.png 8bpp 364 240 8 4 -31 13 normal + -1 sprites/toyland.png 8bpp 380 240 15 4 -7 0 normal + + -1 sprites/toyland.png 8bpp 10 270 38 20 -5 -8 normal + -1 sprites/toyland.png 8bpp 58 270 38 26 -5 5 normal + -1 sprites/toyland.png 8bpp 106 270 37 20 -31 11 normal + -1 sprites/toyland.png 8bpp 154 270 38 27 -31 -8 normal + -1 sprites/toyland.png 8bpp 202 270 16 9 17 3 normal + -1 sprites/toyland.png 8bpp 234 270 15 9 -7 22 normal + -1 sprites/toyland.png 8bpp 266 270 16 9 -31 11 normal + -1 sprites/toyland.png 8bpp 298 270 15 9 -6 -8 normal + -1 sprites/toyland.png 8bpp 330 270 8 7 25 5 normal + -1 sprites/toyland.png 8bpp 346 270 10 5 -4 27 normal + -1 sprites/toyland.png 8bpp 364 270 8 7 -31 11 normal + -1 sprites/toyland.png 8bpp 380 270 12 6 -5 -8 normal + + -1 sprites/toyland.png 8bpp 10 300 39 18 -6 0 normal + -1 sprites/toyland.png 8bpp 58 300 38 11 -5 12 normal + -1 sprites/toyland.png 8bpp 106 300 39 18 -31 5 normal + -1 sprites/toyland.png 8bpp 154 300 40 11 -32 0 normal + -1 sprites/toyland.png 8bpp 202 300 20 6 13 12 normal + -1 sprites/toyland.png 8bpp 234 300 13 7 -5 16 normal + -1 sprites/toyland.png 8bpp 266 300 20 6 -31 5 normal + -1 sprites/toyland.png 8bpp 298 300 13 7 -6 0 normal + -1 sprites/toyland.png 8bpp 330 300 8 4 26 13 normal + -1 sprites/toyland.png 8bpp 346 300 12 3 -5 20 normal + -1 sprites/toyland.png 8bpp 364 300 8 5 -31 6 normal + -1 sprites/toyland.png 8bpp 380 300 15 4 -6 0 normal + + -1 sprites/toyland.png 8bpp 10 330 38 27 -5 -8 normal + -1 sprites/toyland.png 8bpp 58 330 37 20 -4 11 normal + -1 sprites/toyland.png 8bpp 106 330 37 26 -31 5 normal + -1 sprites/toyland.png 8bpp 154 330 38 20 -31 -8 normal + -1 sprites/toyland.png 8bpp 202 330 16 9 17 11 normal + -1 sprites/toyland.png 8bpp 234 330 15 9 -6 22 normal + -1 sprites/toyland.png 8bpp 266 330 16 9 -31 3 normal + -1 sprites/toyland.png 8bpp 298 330 15 9 -7 -8 normal + -1 sprites/toyland.png 8bpp 330 330 8 7 25 11 normal + -1 sprites/toyland.png 8bpp 346 330 10 5 -4 26 normal + -1 sprites/toyland.png 8bpp 364 330 8 7 -31 5 normal + -1 sprites/toyland.png 8bpp 380 330 12 6 -5 -8 normal + -1 * 7 02 05 51 01 00 00 00 + + -1 * 14 02 05 52 81 80 00 FF 01 50 00 00 00 51 00 + -1 * 6 07 83 01 \7! 03 01 + -1 * 7 03 05 01 06 00 52 00 diff --git a/media/extra_grf/rivers/toyland.png b/media/extra_grf/rivers/toyland.png new file mode 100644 index 0000000..61ff224 Binary files /dev/null and b/media/extra_grf/rivers/toyland.png differ diff --git a/media/extra_grf/rivers/tropic.nfo b/media/extra_grf/rivers/tropic.nfo new file mode 100644 index 0000000..b1fa4cf --- /dev/null +++ b/media/extra_grf/rivers/tropic.nfo @@ -0,0 +1,282 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// + -1 * 0 0C "Tropic river graphics by andythenorth (Andrew Parkhouse)" + -1 * 4 01 05 01 3C + -1 sprites/tropic_desert.png 8bpp 10 10 38 19 -5 0 normal + -1 sprites/tropic_desert.png 8bpp 58 10 38 18 -5 13 normal + -1 sprites/tropic_desert.png 8bpp 106 10 38 18 -31 13 normal + -1 sprites/tropic_desert.png 8bpp 154 10 38 19 -31 0 normal + -1 sprites/tropic_desert.png 8bpp 202 10 19 9 14 11 normal + -1 sprites/tropic_desert.png 8bpp 234 10 16 9 -7 22 normal + -1 sprites/tropic_desert.png 8bpp 266 10 19 9 -31 11 normal + -1 sprites/tropic_desert.png 8bpp 298 10 16 9 -7 0 normal + -1 sprites/tropic_desert.png 8bpp 330 10 8 6 25 13 normal + -1 sprites/tropic_desert.png 8bpp 346 10 12 4 -5 27 normal + -1 sprites/tropic_desert.png 8bpp 364 10 8 6 -31 13 normal + -1 sprites/tropic_desert.png 8bpp 380 10 12 5 -5 0 normal + + -1 sprites/tropic_desert.png 8bpp 10 40 40 11 -7 0 normal + -1 sprites/tropic_desert.png 8bpp 58 40 39 18 -6 5 normal + -1 sprites/tropic_desert.png 8bpp 106 40 38 11 -31 12 normal + -1 sprites/tropic_desert.png 8bpp 154 40 39 18 -31 0 normal + -1 sprites/tropic_desert.png 8bpp 202 40 20 6 13 5 normal + -1 sprites/tropic_desert.png 8bpp 234 40 13 7 -6 16 normal + -1 sprites/tropic_desert.png 8bpp 266 40 20 6 -31 12 normal + -1 sprites/tropic_desert.png 8bpp 298 40 13 7 -5 0 normal + -1 sprites/tropic_desert.png 8bpp 330 40 8 5 25 6 normal + -1 sprites/tropic_desert.png 8bpp 346 40 12 3 -5 20 normal + -1 sprites/tropic_desert.png 8bpp 364 40 8 4 -31 13 normal + -1 sprites/tropic_desert.png 8bpp 380 40 15 4 -7 0 normal + + -1 sprites/tropic_desert.png 8bpp 10 70 38 20 -5 -8 normal + -1 sprites/tropic_desert.png 8bpp 58 70 38 26 -5 5 normal + -1 sprites/tropic_desert.png 8bpp 106 70 37 20 -31 11 normal + -1 sprites/tropic_desert.png 8bpp 154 70 38 27 -31 -8 normal + -1 sprites/tropic_desert.png 8bpp 202 70 16 9 17 3 normal + -1 sprites/tropic_desert.png 8bpp 234 70 15 9 -7 22 normal + -1 sprites/tropic_desert.png 8bpp 266 70 16 9 -31 11 normal + -1 sprites/tropic_desert.png 8bpp 298 70 15 9 -6 -8 normal + -1 sprites/tropic_desert.png 8bpp 330 70 8 7 25 5 normal + -1 sprites/tropic_desert.png 8bpp 346 70 10 5 -4 27 normal + -1 sprites/tropic_desert.png 8bpp 364 70 8 7 -31 11 normal + -1 sprites/tropic_desert.png 8bpp 380 70 12 6 -5 -8 normal + + -1 sprites/tropic_desert.png 8bpp 10 100 39 18 -6 0 normal + -1 sprites/tropic_desert.png 8bpp 58 100 38 11 -5 12 normal + -1 sprites/tropic_desert.png 8bpp 106 100 39 18 -31 5 normal + -1 sprites/tropic_desert.png 8bpp 154 100 40 11 -32 0 normal + -1 sprites/tropic_desert.png 8bpp 202 100 20 6 13 12 normal + -1 sprites/tropic_desert.png 8bpp 234 100 13 7 -5 16 normal + -1 sprites/tropic_desert.png 8bpp 266 100 20 6 -31 5 normal + -1 sprites/tropic_desert.png 8bpp 298 100 13 7 -6 0 normal + -1 sprites/tropic_desert.png 8bpp 330 100 8 4 26 13 normal + -1 sprites/tropic_desert.png 8bpp 346 100 12 3 -5 20 normal + -1 sprites/tropic_desert.png 8bpp 364 100 8 5 -31 6 normal + -1 sprites/tropic_desert.png 8bpp 380 100 15 4 -6 0 normal + + -1 sprites/tropic_desert.png 8bpp 10 130 38 27 -5 -8 normal + -1 sprites/tropic_desert.png 8bpp 58 130 37 20 -4 11 normal + -1 sprites/tropic_desert.png 8bpp 106 130 37 26 -31 5 normal + -1 sprites/tropic_desert.png 8bpp 154 130 38 20 -31 -8 normal + -1 sprites/tropic_desert.png 8bpp 202 130 16 9 17 11 normal + -1 sprites/tropic_desert.png 8bpp 234 130 15 9 -6 22 normal + -1 sprites/tropic_desert.png 8bpp 266 130 16 9 -31 3 normal + -1 sprites/tropic_desert.png 8bpp 298 130 15 9 -7 -8 normal + -1 sprites/tropic_desert.png 8bpp 330 130 8 7 25 11 normal + -1 sprites/tropic_desert.png 8bpp 346 130 10 5 -4 26 normal + -1 sprites/tropic_desert.png 8bpp 364 130 8 7 -31 5 normal + -1 sprites/tropic_desert.png 8bpp 380 130 12 6 -5 -8 normal + -1 * 7 02 05 40 01 00 00 00 + + -1 * 4 01 05 01 3C + -1 sprites/tropic_forest.png 8bpp 10 10 38 19 -5 0 normal + -1 sprites/tropic_forest.png 8bpp 58 10 38 18 -5 13 normal + -1 sprites/tropic_forest.png 8bpp 106 10 38 18 -31 13 normal + -1 sprites/tropic_forest.png 8bpp 154 10 38 19 -31 0 normal + -1 sprites/tropic_forest.png 8bpp 202 10 19 9 14 11 normal + -1 sprites/tropic_forest.png 8bpp 234 10 16 9 -7 22 normal + -1 sprites/tropic_forest.png 8bpp 266 10 19 9 -31 11 normal + -1 sprites/tropic_forest.png 8bpp 298 10 16 9 -7 0 normal + -1 sprites/tropic_forest.png 8bpp 330 10 8 6 25 13 normal + -1 sprites/tropic_forest.png 8bpp 346 10 12 4 -5 27 normal + -1 sprites/tropic_forest.png 8bpp 364 10 8 6 -31 13 normal + -1 sprites/tropic_forest.png 8bpp 380 10 12 5 -5 0 normal + + -1 sprites/tropic_forest.png 8bpp 10 40 40 11 -7 0 normal + -1 sprites/tropic_forest.png 8bpp 58 40 39 18 -6 5 normal + -1 sprites/tropic_forest.png 8bpp 106 40 38 11 -31 12 normal + -1 sprites/tropic_forest.png 8bpp 154 40 39 18 -31 0 normal + -1 sprites/tropic_forest.png 8bpp 202 40 20 6 13 5 normal + -1 sprites/tropic_forest.png 8bpp 234 40 13 7 -6 16 normal + -1 sprites/tropic_forest.png 8bpp 266 40 20 6 -31 12 normal + -1 sprites/tropic_forest.png 8bpp 298 40 13 7 -5 0 normal + -1 sprites/tropic_forest.png 8bpp 330 40 8 5 25 6 normal + -1 sprites/tropic_forest.png 8bpp 346 40 12 3 -5 20 normal + -1 sprites/tropic_forest.png 8bpp 364 40 8 4 -31 13 normal + -1 sprites/tropic_forest.png 8bpp 380 40 15 4 -7 0 normal + + -1 sprites/tropic_forest.png 8bpp 10 70 38 20 -5 -8 normal + -1 sprites/tropic_forest.png 8bpp 58 70 38 26 -5 5 normal + -1 sprites/tropic_forest.png 8bpp 106 70 37 20 -31 11 normal + -1 sprites/tropic_forest.png 8bpp 154 70 38 27 -31 -8 normal + -1 sprites/tropic_forest.png 8bpp 202 70 16 9 17 3 normal + -1 sprites/tropic_forest.png 8bpp 234 70 15 9 -7 22 normal + -1 sprites/tropic_forest.png 8bpp 266 70 16 9 -31 11 normal + -1 sprites/tropic_forest.png 8bpp 298 70 15 9 -6 -8 normal + -1 sprites/tropic_forest.png 8bpp 330 70 8 7 25 5 normal + -1 sprites/tropic_forest.png 8bpp 346 70 10 5 -4 27 normal + -1 sprites/tropic_forest.png 8bpp 364 70 8 7 -31 11 normal + -1 sprites/tropic_forest.png 8bpp 380 70 12 6 -5 -8 normal + + -1 sprites/tropic_forest.png 8bpp 10 100 39 18 -6 0 normal + -1 sprites/tropic_forest.png 8bpp 58 100 38 11 -5 12 normal + -1 sprites/tropic_forest.png 8bpp 106 100 39 18 -31 5 normal + -1 sprites/tropic_forest.png 8bpp 154 100 40 11 -32 0 normal + -1 sprites/tropic_forest.png 8bpp 202 100 20 6 13 12 normal + -1 sprites/tropic_forest.png 8bpp 234 100 13 7 -5 16 normal + -1 sprites/tropic_forest.png 8bpp 266 100 20 6 -31 5 normal + -1 sprites/tropic_forest.png 8bpp 298 100 13 7 -6 0 normal + -1 sprites/tropic_forest.png 8bpp 330 100 8 4 26 13 normal + -1 sprites/tropic_forest.png 8bpp 346 100 12 3 -5 20 normal + -1 sprites/tropic_forest.png 8bpp 364 100 8 5 -31 6 normal + -1 sprites/tropic_forest.png 8bpp 380 100 15 4 -6 0 normal + + -1 sprites/tropic_forest.png 8bpp 10 130 38 27 -5 -8 normal + -1 sprites/tropic_forest.png 8bpp 58 130 37 20 -4 11 normal + -1 sprites/tropic_forest.png 8bpp 106 130 37 26 -31 5 normal + -1 sprites/tropic_forest.png 8bpp 154 130 38 20 -31 -8 normal + -1 sprites/tropic_forest.png 8bpp 202 130 16 9 17 11 normal + -1 sprites/tropic_forest.png 8bpp 234 130 15 9 -6 22 normal + -1 sprites/tropic_forest.png 8bpp 266 130 16 9 -31 3 normal + -1 sprites/tropic_forest.png 8bpp 298 130 15 9 -7 -8 normal + -1 sprites/tropic_forest.png 8bpp 330 130 8 7 25 11 normal + -1 sprites/tropic_forest.png 8bpp 346 130 10 5 -4 26 normal + -1 sprites/tropic_forest.png 8bpp 364 130 8 7 -31 5 normal + -1 sprites/tropic_forest.png 8bpp 380 130 12 6 -5 -8 normal + -1 * 7 02 05 41 01 00 00 00 + + -1 * 4 01 05 01 3C + -1 sprites/tropic_desert.png 8bpp 10 210 38 19 -5 0 normal + -1 sprites/tropic_desert.png 8bpp 58 210 38 18 -5 13 normal + -1 sprites/tropic_desert.png 8bpp 106 210 38 18 -31 13 normal + -1 sprites/tropic_desert.png 8bpp 154 210 38 19 -31 0 normal + -1 sprites/tropic_desert.png 8bpp 202 210 19 9 14 11 normal + -1 sprites/tropic_desert.png 8bpp 234 210 16 9 -7 22 normal + -1 sprites/tropic_desert.png 8bpp 266 210 19 9 -31 11 normal + -1 sprites/tropic_desert.png 8bpp 298 210 16 9 -7 0 normal + -1 sprites/tropic_desert.png 8bpp 330 210 8 6 25 13 normal + -1 sprites/tropic_desert.png 8bpp 346 210 12 4 -5 27 normal + -1 sprites/tropic_desert.png 8bpp 364 210 8 6 -31 13 normal + -1 sprites/tropic_desert.png 8bpp 380 210 12 5 -5 0 normal + + -1 sprites/tropic_desert.png 8bpp 10 240 40 11 -7 0 normal + -1 sprites/tropic_desert.png 8bpp 58 240 39 18 -6 5 normal + -1 sprites/tropic_desert.png 8bpp 106 240 38 11 -31 12 normal + -1 sprites/tropic_desert.png 8bpp 154 240 39 18 -31 0 normal + -1 sprites/tropic_desert.png 8bpp 202 240 20 6 13 5 normal + -1 sprites/tropic_desert.png 8bpp 234 240 13 7 -6 16 normal + -1 sprites/tropic_desert.png 8bpp 266 240 20 6 -31 12 normal + -1 sprites/tropic_desert.png 8bpp 298 240 13 7 -5 0 normal + -1 sprites/tropic_desert.png 8bpp 330 240 8 5 25 6 normal + -1 sprites/tropic_desert.png 8bpp 346 240 12 3 -5 20 normal + -1 sprites/tropic_desert.png 8bpp 364 240 8 4 -31 13 normal + -1 sprites/tropic_desert.png 8bpp 380 240 15 4 -7 0 normal + + -1 sprites/tropic_desert.png 8bpp 10 270 38 20 -5 -8 normal + -1 sprites/tropic_desert.png 8bpp 58 270 38 26 -5 5 normal + -1 sprites/tropic_desert.png 8bpp 106 270 37 20 -31 11 normal + -1 sprites/tropic_desert.png 8bpp 154 270 38 27 -31 -8 normal + -1 sprites/tropic_desert.png 8bpp 202 270 16 9 17 3 normal + -1 sprites/tropic_desert.png 8bpp 234 270 15 9 -7 22 normal + -1 sprites/tropic_desert.png 8bpp 266 270 16 9 -31 11 normal + -1 sprites/tropic_desert.png 8bpp 298 270 15 9 -6 -8 normal + -1 sprites/tropic_desert.png 8bpp 330 270 8 7 25 5 normal + -1 sprites/tropic_desert.png 8bpp 346 270 10 5 -4 27 normal + -1 sprites/tropic_desert.png 8bpp 364 270 8 7 -31 11 normal + -1 sprites/tropic_desert.png 8bpp 380 270 12 6 -5 -8 normal + + -1 sprites/tropic_desert.png 8bpp 10 300 39 18 -6 0 normal + -1 sprites/tropic_desert.png 8bpp 58 300 38 11 -5 12 normal + -1 sprites/tropic_desert.png 8bpp 106 300 39 18 -31 5 normal + -1 sprites/tropic_desert.png 8bpp 154 300 40 11 -32 0 normal + -1 sprites/tropic_desert.png 8bpp 202 300 20 6 13 12 normal + -1 sprites/tropic_desert.png 8bpp 234 300 13 7 -5 16 normal + -1 sprites/tropic_desert.png 8bpp 266 300 20 6 -31 5 normal + -1 sprites/tropic_desert.png 8bpp 298 300 13 7 -6 0 normal + -1 sprites/tropic_desert.png 8bpp 330 300 8 4 26 13 normal + -1 sprites/tropic_desert.png 8bpp 346 300 12 3 -5 20 normal + -1 sprites/tropic_desert.png 8bpp 364 300 8 5 -31 6 normal + -1 sprites/tropic_desert.png 8bpp 380 300 15 4 -6 0 normal + + -1 sprites/tropic_desert.png 8bpp 10 330 38 27 -5 -8 normal + -1 sprites/tropic_desert.png 8bpp 58 330 37 20 -4 11 normal + -1 sprites/tropic_desert.png 8bpp 106 330 37 26 -31 5 normal + -1 sprites/tropic_desert.png 8bpp 154 330 38 20 -31 -8 normal + -1 sprites/tropic_desert.png 8bpp 202 330 16 9 17 11 normal + -1 sprites/tropic_desert.png 8bpp 234 330 15 9 -6 22 normal + -1 sprites/tropic_desert.png 8bpp 266 330 16 9 -31 3 normal + -1 sprites/tropic_desert.png 8bpp 298 330 15 9 -7 -8 normal + -1 sprites/tropic_desert.png 8bpp 330 330 8 7 25 11 normal + -1 sprites/tropic_desert.png 8bpp 346 330 10 5 -4 26 normal + -1 sprites/tropic_desert.png 8bpp 364 330 8 7 -31 5 normal + -1 sprites/tropic_desert.png 8bpp 380 330 12 6 -5 -8 normal + -1 * 7 02 05 42 01 00 00 00 + + -1 * 4 01 05 01 3C + -1 sprites/tropic_forest.png 8bpp 10 210 38 19 -5 0 normal + -1 sprites/tropic_forest.png 8bpp 58 210 38 18 -5 13 normal + -1 sprites/tropic_forest.png 8bpp 106 210 38 18 -31 13 normal + -1 sprites/tropic_forest.png 8bpp 154 210 38 19 -31 0 normal + -1 sprites/tropic_forest.png 8bpp 202 210 19 9 14 11 normal + -1 sprites/tropic_forest.png 8bpp 234 210 16 9 -7 22 normal + -1 sprites/tropic_forest.png 8bpp 266 210 19 9 -31 11 normal + -1 sprites/tropic_forest.png 8bpp 298 210 16 9 -7 0 normal + -1 sprites/tropic_forest.png 8bpp 330 210 8 6 25 13 normal + -1 sprites/tropic_forest.png 8bpp 346 210 12 4 -5 27 normal + -1 sprites/tropic_forest.png 8bpp 364 210 8 6 -31 13 normal + -1 sprites/tropic_forest.png 8bpp 380 210 12 5 -5 0 normal + + -1 sprites/tropic_forest.png 8bpp 10 240 40 11 -7 0 normal + -1 sprites/tropic_forest.png 8bpp 58 240 39 18 -6 5 normal + -1 sprites/tropic_forest.png 8bpp 106 240 38 11 -31 12 normal + -1 sprites/tropic_forest.png 8bpp 154 240 39 18 -31 0 normal + -1 sprites/tropic_forest.png 8bpp 202 240 20 6 13 5 normal + -1 sprites/tropic_forest.png 8bpp 234 240 13 7 -6 16 normal + -1 sprites/tropic_forest.png 8bpp 266 240 20 6 -31 12 normal + -1 sprites/tropic_forest.png 8bpp 298 240 13 7 -5 0 normal + -1 sprites/tropic_forest.png 8bpp 330 240 8 5 25 6 normal + -1 sprites/tropic_forest.png 8bpp 346 240 12 3 -5 20 normal + -1 sprites/tropic_forest.png 8bpp 364 240 8 4 -31 13 normal + -1 sprites/tropic_forest.png 8bpp 380 240 15 4 -7 0 normal + + -1 sprites/tropic_forest.png 8bpp 10 270 38 20 -5 -8 normal + -1 sprites/tropic_forest.png 8bpp 58 270 38 26 -5 5 normal + -1 sprites/tropic_forest.png 8bpp 106 270 37 20 -31 11 normal + -1 sprites/tropic_forest.png 8bpp 154 270 38 27 -31 -8 normal + -1 sprites/tropic_forest.png 8bpp 202 270 16 9 17 3 normal + -1 sprites/tropic_forest.png 8bpp 234 270 15 9 -7 22 normal + -1 sprites/tropic_forest.png 8bpp 266 270 16 9 -31 11 normal + -1 sprites/tropic_forest.png 8bpp 298 270 15 9 -6 -8 normal + -1 sprites/tropic_forest.png 8bpp 330 270 8 7 25 5 normal + -1 sprites/tropic_forest.png 8bpp 346 270 10 5 -4 27 normal + -1 sprites/tropic_forest.png 8bpp 364 270 8 7 -31 11 normal + -1 sprites/tropic_forest.png 8bpp 380 270 12 6 -5 -8 normal + + -1 sprites/tropic_forest.png 8bpp 10 300 39 18 -6 0 normal + -1 sprites/tropic_forest.png 8bpp 58 300 38 11 -5 12 normal + -1 sprites/tropic_forest.png 8bpp 106 300 39 18 -31 5 normal + -1 sprites/tropic_forest.png 8bpp 154 300 40 11 -32 0 normal + -1 sprites/tropic_forest.png 8bpp 202 300 20 6 13 12 normal + -1 sprites/tropic_forest.png 8bpp 234 300 13 7 -5 16 normal + -1 sprites/tropic_forest.png 8bpp 266 300 20 6 -31 5 normal + -1 sprites/tropic_forest.png 8bpp 298 300 13 7 -6 0 normal + -1 sprites/tropic_forest.png 8bpp 330 300 8 4 26 13 normal + -1 sprites/tropic_forest.png 8bpp 346 300 12 3 -5 20 normal + -1 sprites/tropic_forest.png 8bpp 364 300 8 5 -31 6 normal + -1 sprites/tropic_forest.png 8bpp 380 300 15 4 -6 0 normal + + -1 sprites/tropic_forest.png 8bpp 10 330 38 27 -5 -8 normal + -1 sprites/tropic_forest.png 8bpp 58 330 37 20 -4 11 normal + -1 sprites/tropic_forest.png 8bpp 106 330 37 26 -31 5 normal + -1 sprites/tropic_forest.png 8bpp 154 330 38 20 -31 -8 normal + -1 sprites/tropic_forest.png 8bpp 202 330 16 9 17 11 normal + -1 sprites/tropic_forest.png 8bpp 234 330 15 9 -6 22 normal + -1 sprites/tropic_forest.png 8bpp 266 330 16 9 -31 3 normal + -1 sprites/tropic_forest.png 8bpp 298 330 15 9 -7 -8 normal + -1 sprites/tropic_forest.png 8bpp 330 330 8 7 25 11 normal + -1 sprites/tropic_forest.png 8bpp 346 330 10 5 -4 26 normal + -1 sprites/tropic_forest.png 8bpp 364 330 8 7 -31 5 normal + -1 sprites/tropic_forest.png 8bpp 380 330 12 6 -5 -8 normal + -1 * 7 02 05 43 01 00 00 00 + + -1 * 14 02 05 44 81 81 00 FF 01 40 00 01 01 41 00 + -1 * 14 02 05 45 81 81 00 FF 01 42 00 01 01 43 00 + -1 * 14 02 05 46 81 80 00 FF 01 44 00 00 00 45 00 + -1 * 6 07 83 01 \7! 02 01 + -1 * 7 03 05 01 06 00 46 00 diff --git a/media/extra_grf/rivers/tropic_desert.png b/media/extra_grf/rivers/tropic_desert.png new file mode 100644 index 0000000..8684686 Binary files /dev/null and b/media/extra_grf/rivers/tropic_desert.png differ diff --git a/media/extra_grf/rivers/tropic_forest.png b/media/extra_grf/rivers/tropic_forest.png new file mode 100644 index 0000000..1aa21e4 Binary files /dev/null and b/media/extra_grf/rivers/tropic_forest.png differ diff --git a/media/extra_grf/roadstops.nfo b/media/extra_grf/roadstops.nfo new file mode 100644 index 0000000..dbb7021 --- /dev/null +++ b/media/extra_grf/roadstops.nfo @@ -0,0 +1,18 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// + -1 * 0 0C "Road stop graphics" + -1 * 3 05 11 08 + -1 sprites/roadstops.png 8bpp 34 8 13 23 5 -11 normal + -1 sprites/roadstops.png 8bpp 66 8 13 15 5 -2 normal + -1 sprites/roadstops.png 8bpp 98 8 21 19 -20 -7 normal + -1 sprites/roadstops.png 8bpp 130 8 22 17 -25 -4 normal + -1 sprites/roadstops.png 8bpp 162 8 32 25 -5 -9 normal + -1 sprites/roadstops.png 8bpp 210 8 28 26 -3 -12 normal + -1 sprites/roadstops.png 8bpp 258 8 29 25 -24 -12 normal + -1 sprites/roadstops.png 8bpp 306 8 32 25 -25 -9 normal diff --git a/media/extra_grf/roadstops.png b/media/extra_grf/roadstops.png new file mode 100644 index 0000000..5987924 Binary files /dev/null and b/media/extra_grf/roadstops.png differ diff --git a/media/extra_grf/shore.nfo b/media/extra_grf/shore.nfo new file mode 100644 index 0000000..70fae8f --- /dev/null +++ b/media/extra_grf/shore.nfo @@ -0,0 +1,61 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// + + -1 * 6 07 83 01 \7! 00 0C + -1 * 54 0C "Missing shore tile graphics for the temperate climate" + -1 * 3 05 0D 0A + -1 sprites/shore.png 8bpp 82 8 64 15 -31 0 normal + -1 sprites/shore.png 8bpp 162 8 64 31 -31 -8 normal + -1 sprites/shore.png 8bpp 242 8 64 23 -31 0 normal + -1 sprites/shore.png 8bpp 322 8 64 47 -31 -16 normal + -1 sprites/shore.png 8bpp 402 8 64 31 -31 -8 normal + -1 sprites/shore.png 8bpp 482 8 64 39 -31 -8 normal + -1 sprites/shore.png 8bpp 562 8 64 31 -31 -8 normal + -1 sprites/shore.png 8bpp 642 8 64 31 -31 -8 normal + -1 sprites/shore.png 8bpp 722 8 64 32 -31 -1 normal + -1 sprites/shore.png 8bpp 2 72 64 31 -31 -8 normal + -1 * 6 07 83 01 \7! 01 0C + -1 * 55 0C "Missing shore tile graphics for the sub-arctic climate" + -1 * 3 05 0D 0A + -1 sprites/shore.png 8bpp 130 72 64 15 -31 0 normal + -1 sprites/shore.png 8bpp 210 72 64 31 -31 -8 normal + -1 sprites/shore.png 8bpp 290 72 64 23 -31 0 normal + -1 sprites/shore.png 8bpp 370 72 64 47 -31 -16 normal + -1 sprites/shore.png 8bpp 450 72 64 31 -31 -8 normal + -1 sprites/shore.png 8bpp 530 72 64 39 -31 -8 normal + -1 sprites/shore.png 8bpp 610 72 64 31 -31 -8 normal + -1 sprites/shore.png 8bpp 690 72 64 31 -31 -8 normal + -1 sprites/shore.png 8bpp 2 136 64 32 -31 -1 normal + -1 sprites/shore.png 8bpp 82 136 64 31 -31 -8 normal + -1 * 6 07 83 01 \7! 02 0C + -1 * 57 0C "Missing shore tile graphics for the sub-tropical climate" + -1 * 3 05 0D 0A + -1 sprites/shore.png 8bpp 210 136 64 15 -31 0 normal + -1 sprites/shore.png 8bpp 290 136 64 31 -31 -8 normal + -1 sprites/shore.png 8bpp 370 136 64 23 -31 0 normal + -1 sprites/shore.png 8bpp 450 136 64 47 -31 -16 normal + -1 sprites/shore.png 8bpp 530 136 64 31 -31 -8 normal + -1 sprites/shore.png 8bpp 610 136 64 39 -31 -8 normal + -1 sprites/shore.png 8bpp 690 136 64 31 -31 -8 normal + -1 sprites/shore.png 8bpp 2 200 64 31 -31 -8 normal + -1 sprites/shore.png 8bpp 82 200 64 32 -31 -1 normal + -1 sprites/shore.png 8bpp 162 200 64 31 -31 -8 normal + -1 * 6 07 83 01 \7! 03 0C + -1 * 44 0C "Missing shore tile graphics for the toyland climate" + -1 * 3 05 0D 0A + -1 sprites/shore.png 8bpp 290 200 64 15 -31 0 normal + -1 sprites/shore.png 8bpp 370 200 64 31 -31 -8 normal + -1 sprites/shore.png 8bpp 450 200 64 23 -31 0 normal + -1 sprites/shore.png 8bpp 530 200 64 47 -31 -16 normal + -1 sprites/shore.png 8bpp 610 200 64 31 -31 -8 normal + -1 sprites/shore.png 8bpp 690 200 64 39 -31 -8 normal + -1 sprites/shore.png 8bpp 2 264 64 31 -31 -8 normal + -1 sprites/shore.png 8bpp 82 264 64 31 -31 -8 normal + -1 sprites/shore.png 8bpp 162 264 64 32 -31 -1 normal + -1 sprites/shore.png 8bpp 242 264 64 31 -31 -8 normal diff --git a/media/extra_grf/shore.png b/media/extra_grf/shore.png new file mode 100644 index 0000000..f98333e Binary files /dev/null and b/media/extra_grf/shore.png differ diff --git a/media/extra_grf/signals.nfo b/media/extra_grf/signals.nfo new file mode 100644 index 0000000..a2d2591 --- /dev/null +++ b/media/extra_grf/signals.nfo @@ -0,0 +1,493 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// + -1 * 0 0C "Pre-signal, semaphore, and PBS graphics by Michael Blunck" + -1 * 3 05 04 F0 + -1 sprites/signals.png 8bpp 66 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 82 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 98 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 114 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 130 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 146 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 162 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 178 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 194 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 210 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 226 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 242 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 258 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 274 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 290 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 306 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 322 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 338 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 354 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 370 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 386 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 402 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 418 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 434 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 450 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 466 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 482 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 498 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 514 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 530 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 546 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 562 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 578 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 594 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 610 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 626 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 642 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 658 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 674 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 690 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 706 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 722 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 738 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 754 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 770 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 786 8 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 2 40 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 18 40 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 34 40 10 21 -6 -19 normal + -1 sprites/signals.png 8bpp 50 40 7 23 -3 -21 normal + -1 sprites/signals.png 8bpp 66 40 10 21 1 -19 normal + -1 sprites/signals.png 8bpp 82 40 9 21 1 -19 normal + -1 sprites/signals.png 8bpp 98 40 9 21 1 -19 normal + -1 sprites/signals.png 8bpp 114 40 6 23 1 -21 normal + -1 sprites/signals.png 8bpp 130 40 10 21 -7 -19 normal + -1 sprites/signals.png 8bpp 146 40 10 21 -7 -19 normal + -1 sprites/signals.png 8bpp 162 40 2 21 1 -19 normal + -1 sprites/signals.png 8bpp 178 40 2 24 1 -22 normal + -1 sprites/signals.png 8bpp 194 40 2 23 1 -21 normal + -1 sprites/signals.png 8bpp 210 40 2 26 1 -24 normal + -1 sprites/signals.png 8bpp 226 40 11 21 -7 -19 normal + -1 sprites/signals.png 8bpp 242 40 8 21 -4 -19 normal + -1 sprites/signals.png 8bpp 258 40 11 21 1 -19 normal + -1 sprites/signals.png 8bpp 274 40 8 21 1 -19 normal + -1 sprites/signals.png 8bpp 290 40 12 21 -6 -19 normal + -1 sprites/signals.png 8bpp 322 40 9 23 -3 -21 normal + -1 sprites/signals.png 8bpp 338 40 12 21 -1 -19 normal + -1 sprites/signals.png 8bpp 370 40 11 21 -1 -19 normal + -1 sprites/signals.png 8bpp 386 40 11 21 -1 -19 normal + -1 sprites/signals.png 8bpp 402 40 8 23 -1 -21 normal + -1 sprites/signals.png 8bpp 418 40 12 21 -7 -19 normal + -1 sprites/signals.png 8bpp 450 40 12 21 -7 -19 normal + -1 sprites/signals.png 8bpp 482 40 4 21 1 -19 normal + -1 sprites/signals.png 8bpp 498 40 4 24 1 -22 normal + -1 sprites/signals.png 8bpp 514 40 4 23 -1 -21 normal + -1 sprites/signals.png 8bpp 530 40 4 26 -1 -24 normal + -1 sprites/signals.png 8bpp 546 40 13 21 -7 -19 normal + -1 sprites/signals.png 8bpp 578 40 10 21 -4 -19 normal + -1 sprites/signals.png 8bpp 594 40 13 21 -1 -19 normal + -1 sprites/signals.png 8bpp 626 40 10 21 -1 -19 normal + -1 sprites/signals.png 8bpp 642 40 11 21 -6 -19 normal + -1 sprites/signals.png 8bpp 658 40 8 23 -3 -21 normal + -1 sprites/signals.png 8bpp 674 40 11 21 0 -19 normal + -1 sprites/signals.png 8bpp 690 40 10 21 0 -19 normal + -1 sprites/signals.png 8bpp 706 40 10 21 0 -19 normal + -1 sprites/signals.png 8bpp 722 40 7 23 0 -21 normal + -1 sprites/signals.png 8bpp 738 40 11 21 -7 -19 normal + -1 sprites/signals.png 8bpp 754 40 11 21 -7 -19 normal + -1 sprites/signals.png 8bpp 770 40 4 21 1 -19 normal + -1 sprites/signals.png 8bpp 786 40 4 24 1 -22 normal + -1 sprites/signals.png 8bpp 2 88 4 23 -1 -21 normal + -1 sprites/signals.png 8bpp 18 88 4 26 -1 -24 normal + -1 sprites/signals.png 8bpp 34 88 12 21 -7 -19 normal + -1 sprites/signals.png 8bpp 66 88 9 21 -4 -19 normal + -1 sprites/signals.png 8bpp 82 88 12 21 0 -19 normal + -1 sprites/signals.png 8bpp 114 88 9 21 0 -19 normal + -1 sprites/signals.png 8bpp 130 88 11 21 -6 -19 normal + -1 sprites/signals.png 8bpp 146 88 8 23 -3 -21 normal + -1 sprites/signals.png 8bpp 162 88 11 21 0 -19 normal + -1 sprites/signals.png 8bpp 178 88 10 21 0 -19 normal + -1 sprites/signals.png 8bpp 194 88 10 21 0 -19 normal + -1 sprites/signals.png 8bpp 210 88 7 23 0 -21 normal + -1 sprites/signals.png 8bpp 226 88 11 21 -7 -19 normal + -1 sprites/signals.png 8bpp 242 88 11 21 -7 -19 normal + -1 sprites/signals.png 8bpp 258 88 4 21 1 -19 normal + -1 sprites/signals.png 8bpp 274 88 4 24 1 -22 normal + -1 sprites/signals.png 8bpp 290 88 4 23 -1 -21 normal + -1 sprites/signals.png 8bpp 306 88 4 26 -1 -24 normal + -1 sprites/signals.png 8bpp 322 88 12 21 -7 -19 normal + -1 sprites/signals.png 8bpp 354 88 9 21 -4 -19 normal + -1 sprites/signals.png 8bpp 370 88 12 21 0 -19 normal + -1 sprites/signals.png 8bpp 402 88 9 21 0 -19 normal + -1 sprites/signals.png 8bpp 418 88 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 434 88 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 450 88 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 466 88 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 482 88 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 498 88 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 514 88 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 530 88 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 546 88 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 562 88 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 578 88 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 594 88 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 610 88 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 626 88 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 642 88 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 658 88 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 674 88 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 690 88 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 706 88 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 722 88 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 738 88 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 754 88 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 770 88 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 786 88 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 2 136 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 18 136 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 34 136 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 50 136 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 66 136 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 82 136 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 98 136 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 114 136 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 130 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 146 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 162 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 178 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 194 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 210 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 226 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 242 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 258 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 274 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 290 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 306 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 322 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 338 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 354 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 370 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 386 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 402 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 418 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 434 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 450 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 466 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 482 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 498 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 514 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 530 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 546 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 562 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 578 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 594 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 610 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 626 136 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 642 136 10 21 -6 -19 normal + -1 sprites/signals.png 8bpp 658 136 7 23 -3 -21 normal + -1 sprites/signals.png 8bpp 674 136 10 21 1 -19 normal + -1 sprites/signals.png 8bpp 690 136 9 21 1 -19 normal + -1 sprites/signals.png 8bpp 706 136 9 21 1 -19 normal + -1 sprites/signals.png 8bpp 722 136 6 23 1 -21 normal + -1 sprites/signals.png 8bpp 738 136 10 21 -7 -19 normal + -1 sprites/signals.png 8bpp 754 136 10 21 -7 -19 normal + -1 sprites/signals.png 8bpp 770 136 2 21 1 -19 normal + -1 sprites/signals.png 8bpp 786 136 2 24 1 -22 normal + -1 sprites/signals.png 8bpp 2 184 2 23 1 -21 normal + -1 sprites/signals.png 8bpp 18 184 2 26 1 -24 normal + -1 sprites/signals.png 8bpp 34 184 11 21 -7 -19 normal + -1 sprites/signals.png 8bpp 50 184 8 21 -4 -19 normal + -1 sprites/signals.png 8bpp 66 184 11 21 1 -19 normal + -1 sprites/signals.png 8bpp 82 184 8 21 1 -19 normal + -1 sprites/signals.png 8bpp 98 184 12 21 -6 -19 normal + -1 sprites/signals.png 8bpp 130 184 9 23 -3 -21 normal + -1 sprites/signals.png 8bpp 146 184 12 21 -1 -19 normal + -1 sprites/signals.png 8bpp 178 184 11 21 -1 -19 normal + -1 sprites/signals.png 8bpp 194 184 11 21 -1 -19 normal + -1 sprites/signals.png 8bpp 210 184 8 23 -1 -21 normal + -1 sprites/signals.png 8bpp 226 184 12 21 -7 -19 normal + -1 sprites/signals.png 8bpp 258 184 12 21 -7 -19 normal + -1 sprites/signals.png 8bpp 290 184 4 21 -1 -19 normal + -1 sprites/signals.png 8bpp 306 184 4 24 -1 -22 normal + -1 sprites/signals.png 8bpp 322 184 4 23 1 -21 normal + -1 sprites/signals.png 8bpp 338 184 4 26 1 -24 normal + -1 sprites/signals.png 8bpp 354 184 13 21 -7 -19 normal + -1 sprites/signals.png 8bpp 386 184 10 21 -4 -19 normal + -1 sprites/signals.png 8bpp 402 184 13 21 -1 -19 normal + -1 sprites/signals.png 8bpp 434 184 10 21 -1 -19 normal + -1 sprites/signals.png 8bpp 450 184 11 21 -6 -19 normal + -1 sprites/signals.png 8bpp 466 184 8 23 -3 -21 normal + -1 sprites/signals.png 8bpp 482 184 11 21 0 -19 normal + -1 sprites/signals.png 8bpp 498 184 10 21 0 -19 normal + -1 sprites/signals.png 8bpp 514 184 10 21 0 -19 normal + -1 sprites/signals.png 8bpp 530 184 7 23 0 -21 normal + -1 sprites/signals.png 8bpp 546 184 11 21 -7 -19 normal + -1 sprites/signals.png 8bpp 562 184 11 21 -7 -19 normal + -1 sprites/signals.png 8bpp 578 184 4 21 1 -19 normal + -1 sprites/signals.png 8bpp 594 184 4 24 1 -22 normal + -1 sprites/signals.png 8bpp 610 184 4 23 -1 -21 normal + -1 sprites/signals.png 8bpp 626 184 4 26 -1 -24 normal + -1 sprites/signals.png 8bpp 642 184 12 21 -7 -19 normal + -1 sprites/signals.png 8bpp 674 184 9 21 -4 -19 normal + -1 sprites/signals.png 8bpp 690 184 12 21 0 -19 normal + -1 sprites/signals.png 8bpp 722 184 9 21 0 -19 normal + -1 sprites/signals.png 8bpp 738 184 11 21 -6 -19 normal + -1 sprites/signals.png 8bpp 754 184 8 23 -3 -21 normal + -1 sprites/signals.png 8bpp 770 184 11 21 0 -19 normal + -1 sprites/signals.png 8bpp 786 184 10 21 0 -19 normal + -1 sprites/signals.png 8bpp 2 232 10 21 0 -19 normal + -1 sprites/signals.png 8bpp 18 232 7 23 0 -21 normal + -1 sprites/signals.png 8bpp 34 232 11 21 -7 -19 normal + -1 sprites/signals.png 8bpp 50 232 11 21 -7 -19 normal + -1 sprites/signals.png 8bpp 66 232 4 21 1 -19 normal + -1 sprites/signals.png 8bpp 82 232 4 24 1 -22 normal + -1 sprites/signals.png 8bpp 98 232 4 23 -1 -21 normal + -1 sprites/signals.png 8bpp 114 232 4 26 -1 -24 normal + -1 sprites/signals.png 8bpp 130 232 12 21 -7 -19 normal + -1 sprites/signals.png 8bpp 162 232 9 21 -4 -19 normal + -1 sprites/signals.png 8bpp 178 232 12 21 0 -19 normal + -1 sprites/signals.png 8bpp 210 232 9 21 0 -19 normal + -1 * 6 07 85 01 \70 3B F2 + -1 * 6 07 86 01 \70 04 F1 + -1 * 3 05 04 F0 + -1 sprites/signals.png 8bpp 274 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 290 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 306 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 322 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 338 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 354 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 370 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 386 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 402 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 418 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 434 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 450 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 466 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 482 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 498 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 514 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 530 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 546 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 562 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 578 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 594 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 610 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 626 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 642 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 658 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 674 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 690 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 706 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 722 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 738 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 754 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 770 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 786 232 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 2 280 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 18 280 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 34 280 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 50 280 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 66 280 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 82 280 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 98 280 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 114 280 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 130 280 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 146 280 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 162 280 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 178 280 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 194 280 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 210 280 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 226 280 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 242 280 10 21 -7 -19 normal + -1 sprites/signals.png 8bpp 258 280 10 23 -8 -21 normal + -1 sprites/signals.png 8bpp 274 280 10 23 -7 -21 normal + -1 sprites/signals.png 8bpp 290 280 7 26 -5 -24 normal + -1 sprites/signals.png 8bpp 306 280 10 21 -7 -19 normal + -1 sprites/signals.png 8bpp 322 280 10 23 -6 -21 normal + -1 sprites/signals.png 8bpp 338 280 10 23 1 -21 normal + -1 sprites/signals.png 8bpp 354 280 7 26 2 -24 normal + -1 sprites/signals.png 8bpp 370 280 3 23 0 -21 normal + -1 sprites/signals.png 8bpp 386 280 3 26 0 -24 normal + -1 sprites/signals.png 8bpp 402 280 3 21 0 -19 normal + -1 sprites/signals.png 8bpp 418 280 3 24 0 -22 normal + -1 sprites/signals.png 8bpp 434 280 12 21 0 -19 normal + -1 sprites/signals.png 8bpp 466 280 9 24 0 -22 normal + -1 sprites/signals.png 8bpp 482 280 12 21 -9 -19 normal + -1 sprites/signals.png 8bpp 514 280 9 24 -6 -22 normal + -1 sprites/signals.png 8bpp 530 280 12 21 -9 -19 normal + -1 sprites/signals.png 8bpp 562 280 11 23 -9 -21 normal + -1 sprites/signals.png 8bpp 578 280 11 23 -7 -21 normal + -1 sprites/signals.png 8bpp 594 280 9 26 -5 -24 normal + -1 sprites/signals.png 8bpp 610 280 12 21 -7 -19 normal + -1 sprites/signals.png 8bpp 642 280 11 23 -6 -21 normal + -1 sprites/signals.png 8bpp 658 280 11 23 0 -21 normal + -1 sprites/signals.png 8bpp 674 280 9 26 0 -24 normal + -1 sprites/signals.png 8bpp 690 280 5 23 0 -21 normal + -1 sprites/signals.png 8bpp 706 280 5 26 0 -24 normal + -1 sprites/signals.png 8bpp 722 280 5 21 -2 -19 normal + -1 sprites/signals.png 8bpp 738 280 5 24 -2 -22 normal + -1 sprites/signals.png 8bpp 754 280 13 21 -1 -19 normal + -1 sprites/signals.png 8bpp 786 280 10 24 -1 -22 normal + -1 sprites/signals.png 8bpp 2 328 13 21 -9 -19 normal + -1 sprites/signals.png 8bpp 34 328 10 24 -6 -22 normal + -1 sprites/signals.png 8bpp 50 328 11 21 -8 -19 normal + -1 sprites/signals.png 8bpp 66 328 10 23 -8 -21 normal + -1 sprites/signals.png 8bpp 82 328 10 23 -7 -21 normal + -1 sprites/signals.png 8bpp 98 328 8 26 -5 -24 normal + -1 sprites/signals.png 8bpp 114 328 11 21 -7 -19 normal + -1 sprites/signals.png 8bpp 130 328 10 23 -6 -21 normal + -1 sprites/signals.png 8bpp 146 328 10 23 1 -21 normal + -1 sprites/signals.png 8bpp 162 328 8 26 1 -24 normal + -1 sprites/signals.png 8bpp 178 328 5 23 0 -21 normal + -1 sprites/signals.png 8bpp 194 328 5 26 0 -24 normal + -1 sprites/signals.png 8bpp 210 328 5 21 -2 -19 normal + -1 sprites/signals.png 8bpp 226 328 5 24 -2 -22 normal + -1 sprites/signals.png 8bpp 242 328 12 21 0 -19 normal + -1 sprites/signals.png 8bpp 274 328 9 24 0 -22 normal + -1 sprites/signals.png 8bpp 290 328 12 21 -9 -19 normal + -1 sprites/signals.png 8bpp 322 328 9 24 -6 -22 normal + -1 sprites/signals.png 8bpp 338 328 11 21 -8 -19 normal + -1 sprites/signals.png 8bpp 354 328 10 23 -8 -21 normal + -1 sprites/signals.png 8bpp 370 328 10 23 -7 -21 normal + -1 sprites/signals.png 8bpp 386 328 8 26 -5 -24 normal + -1 sprites/signals.png 8bpp 402 328 11 21 -7 -19 normal + -1 sprites/signals.png 8bpp 418 328 10 23 -6 -21 normal + -1 sprites/signals.png 8bpp 434 328 10 23 1 -21 normal + -1 sprites/signals.png 8bpp 450 328 8 26 1 -24 normal + -1 sprites/signals.png 8bpp 466 328 5 23 0 -21 normal + -1 sprites/signals.png 8bpp 482 328 5 26 0 -24 normal + -1 sprites/signals.png 8bpp 498 328 5 21 -2 -19 normal + -1 sprites/signals.png 8bpp 514 328 5 24 -2 -22 normal + -1 sprites/signals.png 8bpp 530 328 12 21 0 -19 normal + -1 sprites/signals.png 8bpp 562 328 9 24 0 -22 normal + -1 sprites/signals.png 8bpp 578 328 12 21 -9 -19 normal + -1 sprites/signals.png 8bpp 610 328 9 24 -6 -22 normal + -1 sprites/signals.png 8bpp 626 328 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 642 328 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 658 328 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 674 328 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 690 328 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 706 328 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 722 328 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 738 328 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 754 328 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 770 328 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 786 328 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 2 376 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 18 376 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 34 376 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 50 376 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 66 376 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 82 376 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 98 376 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 114 376 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 130 376 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 146 376 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 162 376 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 178 376 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 194 376 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 210 376 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 226 376 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 242 376 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 258 376 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 274 376 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 290 376 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 306 376 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 322 376 6 19 -2 -17 normal + -1 sprites/signals.png 8bpp 338 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 354 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 370 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 386 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 402 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 418 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 434 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 450 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 466 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 482 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 498 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 514 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 530 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 546 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 562 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 578 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 594 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 610 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 626 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 642 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 658 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 674 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 690 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 706 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 722 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 738 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 754 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 770 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 786 376 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 2 408 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 18 408 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 34 408 6 21 -2 -19 normal + -1 sprites/signals.png 8bpp 50 408 10 21 -7 -19 normal + -1 sprites/signals.png 8bpp 66 408 10 23 -8 -21 normal + -1 sprites/signals.png 8bpp 82 408 10 23 -7 -21 normal + -1 sprites/signals.png 8bpp 98 408 7 26 -5 -24 normal + -1 sprites/signals.png 8bpp 114 408 10 21 -7 -19 normal + -1 sprites/signals.png 8bpp 130 408 10 23 -6 -21 normal + -1 sprites/signals.png 8bpp 146 408 10 23 1 -21 normal + -1 sprites/signals.png 8bpp 162 408 7 26 2 -24 normal + -1 sprites/signals.png 8bpp 178 408 3 23 0 -21 normal + -1 sprites/signals.png 8bpp 194 408 3 26 0 -24 normal + -1 sprites/signals.png 8bpp 210 408 3 21 0 -19 normal + -1 sprites/signals.png 8bpp 226 408 3 24 0 -22 normal + -1 sprites/signals.png 8bpp 242 408 12 21 0 -19 normal + -1 sprites/signals.png 8bpp 274 408 9 24 0 -22 normal + -1 sprites/signals.png 8bpp 290 408 12 21 -9 -19 normal + -1 sprites/signals.png 8bpp 322 408 9 24 -6 -22 normal + -1 sprites/signals.png 8bpp 338 408 12 21 -9 -19 normal + -1 sprites/signals.png 8bpp 370 408 11 23 -9 -21 normal + -1 sprites/signals.png 8bpp 386 408 11 23 -7 -21 normal + -1 sprites/signals.png 8bpp 402 408 9 26 -5 -24 normal + -1 sprites/signals.png 8bpp 418 408 12 21 -7 -19 normal + -1 sprites/signals.png 8bpp 450 408 11 23 -6 -21 normal + -1 sprites/signals.png 8bpp 466 408 11 23 0 -21 normal + -1 sprites/signals.png 8bpp 482 408 9 26 0 -24 normal + -1 sprites/signals.png 8bpp 498 408 5 23 -1 -21 normal + -1 sprites/signals.png 8bpp 514 408 5 26 -1 -24 normal + -1 sprites/signals.png 8bpp 530 408 5 21 -1 -19 normal + -1 sprites/signals.png 8bpp 546 408 5 24 -1 -22 normal + -1 sprites/signals.png 8bpp 562 408 13 21 -1 -19 normal + -1 sprites/signals.png 8bpp 594 408 10 24 -1 -22 normal + -1 sprites/signals.png 8bpp 610 408 13 21 -9 -19 normal + -1 sprites/signals.png 8bpp 642 408 10 24 -6 -22 normal + -1 sprites/signals.png 8bpp 658 408 11 21 -8 -19 normal + -1 sprites/signals.png 8bpp 674 408 10 23 -8 -21 normal + -1 sprites/signals.png 8bpp 690 408 10 23 -7 -21 normal + -1 sprites/signals.png 8bpp 706 408 8 26 -5 -24 normal + -1 sprites/signals.png 8bpp 722 408 11 21 -7 -19 normal + -1 sprites/signals.png 8bpp 738 408 10 23 -6 -21 normal + -1 sprites/signals.png 8bpp 754 408 10 23 1 -21 normal + -1 sprites/signals.png 8bpp 770 408 8 26 1 -24 normal + -1 sprites/signals.png 8bpp 786 408 5 23 0 -21 normal + -1 sprites/signals.png 8bpp 2 456 5 26 0 -24 normal + -1 sprites/signals.png 8bpp 18 456 5 21 -2 -19 normal + -1 sprites/signals.png 8bpp 34 456 5 24 -2 -22 normal + -1 sprites/signals.png 8bpp 50 456 12 21 0 -19 normal + -1 sprites/signals.png 8bpp 82 456 9 24 0 -22 normal + -1 sprites/signals.png 8bpp 98 456 12 21 -9 -19 normal + -1 sprites/signals.png 8bpp 130 456 9 24 -6 -22 normal + -1 sprites/signals.png 8bpp 146 456 11 21 -8 -19 normal + -1 sprites/signals.png 8bpp 162 456 10 23 -8 -21 normal + -1 sprites/signals.png 8bpp 178 456 10 23 -7 -21 normal + -1 sprites/signals.png 8bpp 194 456 8 26 -5 -24 normal + -1 sprites/signals.png 8bpp 210 456 11 21 -7 -19 normal + -1 sprites/signals.png 8bpp 226 456 10 23 -6 -21 normal + -1 sprites/signals.png 8bpp 242 456 10 23 1 -21 normal + -1 sprites/signals.png 8bpp 258 456 8 26 1 -24 normal + -1 sprites/signals.png 8bpp 274 456 5 23 0 -21 normal + -1 sprites/signals.png 8bpp 290 456 5 26 0 -24 normal + -1 sprites/signals.png 8bpp 306 456 5 21 -2 -19 normal + -1 sprites/signals.png 8bpp 322 456 5 24 -2 -22 normal + -1 sprites/signals.png 8bpp 338 456 12 21 0 -19 normal + -1 sprites/signals.png 8bpp 370 456 9 24 0 -22 normal + -1 sprites/signals.png 8bpp 386 456 12 21 -9 -19 normal + -1 sprites/signals.png 8bpp 418 456 9 24 -6 -22 normal diff --git a/media/extra_grf/signals.png b/media/extra_grf/signals.png new file mode 100644 index 0000000..6e0562a Binary files /dev/null and b/media/extra_grf/signals.png differ diff --git a/media/extra_grf/sloped_tracks.nfo b/media/extra_grf/sloped_tracks.nfo new file mode 100644 index 0000000..ed17bc8 --- /dev/null +++ b/media/extra_grf/sloped_tracks.nfo @@ -0,0 +1,22 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// + -1 * 0 0C "Sloped tracks" + -1 * 3 05 0F 0C + -1 sprites/sloped_tracks.png 8bpp 50 8 42 29 -19 -3 normal + -1 sprites/sloped_tracks.png 8bpp 98 8 41 13 -20 5 normal + -1 sprites/sloped_tracks.png 8bpp 146 8 42 14 -19 5 normal + -1 sprites/sloped_tracks.png 8bpp 194 8 42 29 -21 -3 normal + -1 sprites/sloped_tracks.png 8bpp 242 8 33 25 -15 -1 normal + -1 sprites/sloped_tracks.png 8bpp 290 8 33 10 -15 7 normal + -1 sprites/sloped_tracks.png 8bpp 338 8 34 10 -15 7 normal + -1 sprites/sloped_tracks.png 8bpp 386 8 34 25 -15 -1 normal + -1 sprites/sloped_tracks.png 8bpp 434 8 31 23 -13 -1 normal + -1 sprites/sloped_tracks.png 8bpp 482 8 32 10 -15 7 normal + -1 sprites/sloped_tracks.png 8bpp 530 8 31 10 -15 7 normal + -1 sprites/sloped_tracks.png 8bpp 578 8 31 23 -16 -1 normal diff --git a/media/extra_grf/sloped_tracks.png b/media/extra_grf/sloped_tracks.png new file mode 100644 index 0000000..16ace38 Binary files /dev/null and b/media/extra_grf/sloped_tracks.png differ diff --git a/media/extra_grf/tramtracks.nfo b/media/extra_grf/tramtracks.nfo new file mode 100644 index 0000000..5a07819 --- /dev/null +++ b/media/extra_grf/tramtracks.nfo @@ -0,0 +1,123 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// + -1 * 0 0C "Tram track graphics by PikkaBird" + -1 * 3 05 0B 71 + -1 sprites/tramtracks.png 8bpp 18 8 20 13 0 4 normal + -1 sprites/tramtracks.png 8bpp 50 8 20 13 0 4 normal + -1 sprites/tramtracks.png 8bpp 82 8 64 36 -18 -8 normal + -1 sprites/tramtracks.png 8bpp 162 8 62 36 -16 -8 normal + -1 sprites/tramtracks.png 8bpp 242 8 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 322 8 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 402 8 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 482 8 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 562 8 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 642 8 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 722 8 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 2 56 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 82 56 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 162 56 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 242 56 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 322 56 64 39 -31 -8 normal + -1 sprites/tramtracks.png 8bpp 402 56 64 23 -31 0 normal + -1 sprites/tramtracks.png 8bpp 482 56 64 23 -31 0 normal + -1 sprites/tramtracks.png 8bpp 562 56 64 39 -31 -8 normal + -1 sprites/tramtracks.png 8bpp 642 56 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 722 56 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 2 120 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 82 120 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 162 120 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 242 120 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 322 120 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 402 120 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 482 120 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 562 120 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 642 120 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 722 120 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 2 168 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 82 168 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 162 168 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 242 168 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 322 168 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 402 168 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 482 168 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 562 168 64 39 -31 -8 normal + -1 sprites/tramtracks.png 8bpp 642 168 64 23 -31 0 normal + -1 sprites/tramtracks.png 8bpp 722 168 64 23 -31 0 normal + -1 sprites/tramtracks.png 8bpp 2 232 64 39 -31 -8 normal + -1 sprites/tramtracks.png 8bpp 82 232 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 162 232 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 242 232 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 322 232 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 402 232 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 482 232 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 562 232 20 20 0 0 normal + -1 sprites/tramtracks.png 8bpp 594 232 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 674 232 62 64 2 -49 normal + -1 sprites/tramtracks.png 8bpp 2 312 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 82 312 62 64 -62 -49 normal + -1 sprites/tramtracks.png 8bpp 162 312 62 64 -62 -49 normal + -1 sprites/tramtracks.png 8bpp 242 312 62 64 2 -49 normal + -1 sprites/tramtracks.png 8bpp 322 312 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 402 312 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 482 312 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 562 312 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 642 312 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 722 312 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 2 392 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 82 392 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 162 392 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 242 392 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 322 392 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 402 392 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 482 392 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 562 392 64 56 -31 -25 normal + -1 sprites/tramtracks.png 8bpp 642 392 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 722 392 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 2 472 64 56 -31 -25 normal + -1 sprites/tramtracks.png 8bpp 82 472 64 56 -31 -25 normal + -1 sprites/tramtracks.png 8bpp 162 472 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 242 472 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 322 472 64 56 -31 -25 normal + -1 sprites/tramtracks.png 8bpp 402 472 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 482 472 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 562 472 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 642 472 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 722 472 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 2 552 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 82 552 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 162 552 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 242 552 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 322 552 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 402 552 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 482 552 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 562 552 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 642 552 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 722 552 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 2 616 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 82 616 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 162 616 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 242 616 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 322 616 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 402 616 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 482 616 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 562 616 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 642 616 64 56 -31 -25 normal + -1 sprites/tramtracks.png 8bpp 722 616 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 2 696 64 56 -31 -25 normal + -1 sprites/tramtracks.png 8bpp 82 696 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 162 696 64 56 -31 -25 normal + -1 sprites/tramtracks.png 8bpp 242 696 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 322 696 64 56 -31 -25 normal + -1 sprites/tramtracks.png 8bpp 402 696 64 48 -31 -17 normal + -1 sprites/tramtracks.png 8bpp 482 696 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 562 696 64 31 -31 0 normal + -1 sprites/tramtracks.png 8bpp 642 696 64 39 -31 -8 normal + -1 sprites/tramtracks.png 8bpp 722 696 64 23 -31 0 normal + -1 sprites/tramtracks.png 8bpp 2 776 64 23 -31 0 normal + -1 sprites/tramtracks.png 8bpp 82 776 64 39 -31 -8 normal diff --git a/media/extra_grf/tramtracks.png b/media/extra_grf/tramtracks.png new file mode 100644 index 0000000..5e21455 Binary files /dev/null and b/media/extra_grf/tramtracks.png differ diff --git a/media/extra_grf/tunnel_portals.nfo b/media/extra_grf/tunnel_portals.nfo new file mode 100644 index 0000000..711229a --- /dev/null +++ b/media/extra_grf/tunnel_portals.nfo @@ -0,0 +1,74 @@ +// +// $Id$ +// +// This file is part of OpenTTD. +// OpenTTD 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, version 2. +// OpenTTD 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 OpenTTD. If not, see . +// + + -1 * 63 0C "Tunnel portal overlays for railtypes by Snail (Jacopo Coletto)" + +// Tropical sprites. + -1 * 6 07 83 01 \7! 02 11 + -1 * 3 05 17 10 + -1 sprites/tunnel_portals.png 8bpp 5 88 35 33 -31 -2 normal + -1 sprites/tunnel_portals.png 8bpp 43 88 40 37 -7 -38 normal + -1 sprites/tunnel_portals.png 8bpp 86 88 35 21 -31 0 normal + -1 sprites/tunnel_portals.png 8bpp 124 88 40 22 -7 -29 normal + -1 sprites/tunnel_portals.png 8bpp 168 88 35 21 -2 0 normal + -1 sprites/tunnel_portals.png 8bpp 206 88 40 22 -31 -29 normal + -1 sprites/tunnel_portals.png 8bpp 249 88 35 33 -2 -2 normal + -1 sprites/tunnel_portals.png 8bpp 287 88 40 37 -31 -38 normal + -1 sprites/tunnel_portals.png 8bpp 5 170 35 33 -31 -2 normal + -1 sprites/tunnel_portals.png 8bpp 43 170 40 37 -7 -38 normal + -1 sprites/tunnel_portals.png 8bpp 86 170 35 21 -31 0 normal + -1 sprites/tunnel_portals.png 8bpp 124 170 40 22 -7 -29 normal + -1 sprites/tunnel_portals.png 8bpp 168 170 35 21 -2 0 normal + -1 sprites/tunnel_portals.png 8bpp 206 170 40 22 -31 -29 normal + -1 sprites/tunnel_portals.png 8bpp 249 170 35 33 -2 -2 normal + -1 sprites/tunnel_portals.png 8bpp 287 170 40 37 -31 -38 normal + +// Temperate grass + snow sprites. + -1 * 6 07 83 01 \7= 02 25 + -1 * 3 05 17 10 + -1 sprites/tunnel_portals.png 8bpp 5 6 35 33 -31 -2 normal + -1 sprites/tunnel_portals.png 8bpp 43 6 40 37 -7 -38 normal + -1 sprites/tunnel_portals.png 8bpp 86 6 35 21 -31 0 normal + -1 sprites/tunnel_portals.png 8bpp 124 6 40 22 -7 -29 normal + -1 sprites/tunnel_portals.png 8bpp 168 6 35 21 -2 0 normal + -1 sprites/tunnel_portals.png 8bpp 206 6 40 22 -31 -29 normal + -1 sprites/tunnel_portals.png 8bpp 249 6 35 33 -2 -2 normal + -1 sprites/tunnel_portals.png 8bpp 287 6 40 37 -31 -38 normal + -1 sprites/tunnel_portals.png 8bpp 5 129 35 33 -31 -2 normal + -1 sprites/tunnel_portals.png 8bpp 43 129 40 37 -7 -38 normal + -1 sprites/tunnel_portals.png 8bpp 86 129 35 21 -31 0 normal + -1 sprites/tunnel_portals.png 8bpp 124 129 40 22 -7 -29 normal + -1 sprites/tunnel_portals.png 8bpp 168 129 35 21 -2 0 normal + -1 sprites/tunnel_portals.png 8bpp 206 129 40 22 -31 -29 normal + -1 sprites/tunnel_portals.png 8bpp 249 129 35 33 -2 -2 normal + -1 sprites/tunnel_portals.png 8bpp 287 129 40 37 -31 -38 normal + +// Arctic grass sprites. + -1 * 6 07 83 01 \7! 01 09 + -1 * 4 05 97 08 00 + -1 sprites/tunnel_portals.png 8bpp 5 47 35 33 -31 -2 normal + -1 sprites/tunnel_portals.png 8bpp 43 47 40 37 -7 -38 normal + -1 sprites/tunnel_portals.png 8bpp 86 47 35 21 -31 0 normal + -1 sprites/tunnel_portals.png 8bpp 124 47 40 22 -7 -29 normal + -1 sprites/tunnel_portals.png 8bpp 168 47 35 21 -2 0 normal + -1 sprites/tunnel_portals.png 8bpp 206 47 40 22 -31 -29 normal + -1 sprites/tunnel_portals.png 8bpp 249 47 35 33 -2 -2 normal + -1 sprites/tunnel_portals.png 8bpp 287 47 40 37 -31 -38 normal + +// Toyland sprites. + -1 * 6 07 83 01 \7! 03 09 + -1 * 4 05 97 08 00 + -1 sprites/tunnel_portals.png 8bpp 5 211 35 33 -31 -2 normal + -1 sprites/tunnel_portals.png 8bpp 43 211 40 37 -7 -38 normal + -1 sprites/tunnel_portals.png 8bpp 86 211 35 21 -31 0 normal + -1 sprites/tunnel_portals.png 8bpp 124 211 40 22 -7 -29 normal + -1 sprites/tunnel_portals.png 8bpp 168 211 35 21 -2 0 normal + -1 sprites/tunnel_portals.png 8bpp 206 211 40 22 -31 -29 normal + -1 sprites/tunnel_portals.png 8bpp 249 211 35 33 -2 -2 normal + -1 sprites/tunnel_portals.png 8bpp 287 211 40 37 -31 -38 normal diff --git a/media/extra_grf/tunnel_portals.png b/media/extra_grf/tunnel_portals.png new file mode 100644 index 0000000..00abd9c Binary files /dev/null and b/media/extra_grf/tunnel_portals.png differ diff --git a/media/openttd.128.png b/media/openttd.128.png new file mode 100644 index 0000000..750c0ed Binary files /dev/null and b/media/openttd.128.png differ diff --git a/media/openttd.16.png b/media/openttd.16.png new file mode 100644 index 0000000..4991aeb Binary files /dev/null and b/media/openttd.16.png differ diff --git a/media/openttd.256.png b/media/openttd.256.png new file mode 100644 index 0000000..596ad19 Binary files /dev/null and b/media/openttd.256.png differ diff --git a/media/openttd.32.bmp b/media/openttd.32.bmp new file mode 100644 index 0000000..e388628 Binary files /dev/null and b/media/openttd.32.bmp differ diff --git a/media/openttd.32.png b/media/openttd.32.png new file mode 100644 index 0000000..469f16d Binary files /dev/null and b/media/openttd.32.png differ diff --git a/media/openttd.32.xpm b/media/openttd.32.xpm new file mode 100644 index 0000000..9cebcf8 --- /dev/null +++ b/media/openttd.32.xpm @@ -0,0 +1,295 @@ +/* XPM */ +static char *openttd.32[] = { +/* columns rows colors chars-per-pixel */ +"32 32 257 2", +" c #000000", +". c #00000A", +"X c #03090D", +"o c #000017", +"O c #00001C", +"+ c #060D12", +"@ c #060C1C", +"# c #0C131B", +"$ c #0A1117", +"% c #15031F", +"& c #1D1B18", +"* c #0D0024", +"= c #070022", +"- c #0C1827", +"; c #150223", +": c #180324", +"> c #1B0C22", +", c #19002A", +"< c #151825", +"1 c #1A1E34", +"2 c #1A242C", +"3 c #1E2327", +"4 c #1A2630", +"5 c #201825", +"6 c #201427", +"7 c #21262C", +"8 c #24292D", +"9 c #28292B", +"0 c #232C33", +"q c #2C2631", +"w c #3B2C2F", +"e c #352B30", +"r c #37392D", +"t c #313231", +"y c #353C31", +"u c #383532", +"i c #351C43", +"p c #383D42", +"a c #294335", +"s c #2A4C36", +"d c #2C5436", +"f c #2F5935", +"g c #354031", +"h c #384533", +"j c #3B542D", +"k c #315F33", +"l c #326B2E", +"z c #30642F", +"x c #3A762D", +"c c #3B7B2D", +"v c #36712E", +"b c #3E4042", +"n c #432D2D", +"m c #4B312B", +"M c #52352B", +"N c #6B3B29", +"B c #763D21", +"V c #4F335D", +"C c #405C32", +"Z c #5A402A", +"A c #5F4435", +"S c #456B33", +"D c #4D6A3F", +"F c #487434", +"G c #4B7D33", +"H c #537D3F", +"J c #7D401F", +"K c #684527", +"L c #634734", +"P c #7D502B", +"I c #72583A", +"U c #434241", +"Y c #4B4640", +"T c #43484F", +"R c #424C56", +"E c #434D59", +"W c #49535D", +"Q c #46505B", +"! c #544A40", +"~ c #564C59", +"^ c #4C5661", +"/ c #555D65", +"( c #5A4763", +") c #55606B", +"_ c #7F6549", +"` c #63696F", +"' c #6E7377", +"] c #7A6F62", +"[ c #7E7162", +"{ c #7A7C7B", +"} c #3E822D", +"| c #40862D", +" . c #4E8334", +".. c #518B35", +"X. c #508735", +"o. c #5CAB35", +"O. c #5EB335", +"+. c #61BB36", +"@. c #62C435", +"#. c #65CC34", +"$. c #69CF37", +"%. c #66D134", +"&. c #68D532", +"*. c #6BDB35", +"=. c #6EE236", +"-. c #71EA37", +";. c #833C03", +":. c #8A451C", +">. c #83421E", +",. c #944E1B", +"<. c #9A551A", +"1. c #8F5720", +"2. c #835834", +"3. c #995922", +"4. c #8C643C", +"5. c #9B6B3A", +"6. c #AC5306", +"7. c #BE4B00", +"8. c #BA5503", +"9. c #B15D16", +"0. c #A35A1B", +"q. c #BE661D", +"w. c #AE6324", +"e. c #A5743F", +"r. c #B36624", +"t. c #B76E31", +"y. c #BA773B", +"u. c #8A6643", +"i. c #936E47", +"p. c #9A754D", +"a. c #9C7552", +"s. c #907D6C", +"d. c #A67747", +"f. c #A77D50", +"g. c #B27D43", +"h. c #C05900", +"j. c #CD660D", +"k. c #CC6409", +"l. c #DB690A", +"z. c #D96706", +"x. c #D16E18", +"c. c #C16B23", +"v. c #CA762B", +"b. c #D87E30", +"n. c #CB792E", +"m. c #E36E0A", +"M. c #EA6D03", +"N. c #EC7105", +"B. c #F76F00", +"V. c #FE6F00", +"C. c #F37503", +"Z. c #FE7500", +"A. c #FE7A00", +"S. c #FD7C0C", +"D. c #F4790E", +"F. c #FE7E11", +"G. c #C27E42", +"H. c #9D8065", +"J. c #9A8570", +"K. c #BD834E", +"L. c #B5814B", +"P. c #B28452", +"I. c #BF8C56", +"U. c #BE8E63", +"Y. c #B79779", +"T. c #D5863F", +"R. c #FF8209", +"E. c #FE8215", +"W. c #FC821B", +"Q. c #EE8934", +"!. c #FC8623", +"~. c #FF8A23", +"^. c #FA8A2C", +"/. c #FA8728", +"(. c #F98E33", +"). c #F7953E", +"_. c #FC9234", +"`. c #F9933B", +"'. c #FF9B3D", +"]. c #C48B52", +"[. c #CD9456", +"{. c #C79156", +"}. c #D38D44", +"|. c #DA9D5B", +" X c #D39858", +".X c #C48A4A", +"XX c #C99561", +"oX c #C29D7A", +"OX c #C19C76", +"+X c #DEA15F", +"@X c #E18D43", +"#X c #EC9542", +"$X c #E09C52", +"%X c #F59741", +"&X c #F69945", +"*X c #F59D4A", +"=X c #FB9940", +"-X c #F89D49", +";X c #E3A25C", +":X c #EBA55A", +">X c #FFA047", +",X c #FFA74B", +".A.Z.A.6.dXNXm.Z.A.N.n v &.*.=.F : YXYXYXYX", +"YXYXYXYXO y +.=.*.#.s >.A.A.z.K.XXD.A.N.m l &.*.=.G > YXYXYXYXYX", +"YXYXYXYXYX= y +.=.*.@.s :.A.A.Z.Z.A.C.m l &.*.-. .> YXYXYXYXYXYX", +"YXYXYXYXYXYX* y +.=.=.@.s ,.A.Z.A.C.M z &.*.=.X.> YXYXYXYXYXYXYX", +"YXYXYXYXYXYXYX* g @.*.-.G 4 <.A.C.Z - j $.-.X.> YXYXYXYXYXYXYXYX", +"YXYXYXYXYXYXYXYX; h $...< @ 0 <.K - YX, C X.5 YXYXYXYXYXYXYXYX", +"YXYXYXYXYXYXYXYXYX: y 9 YX3 0 2 YXYX6 6 YXYXYXYXYXYXYXYXYX", +"YXYXYXYXYXYXYXYXYXYX. YXYXYX YXYXYXYXYXYXYXYXYXYXYXYXYXYXYX" +}; diff --git a/media/openttd.48.png b/media/openttd.48.png new file mode 100644 index 0000000..fa0d989 Binary files /dev/null and b/media/openttd.48.png differ diff --git a/media/openttd.64.png b/media/openttd.64.png new file mode 100644 index 0000000..a8ad36f Binary files /dev/null and b/media/openttd.64.png differ diff --git a/media/openttd.64.xpm b/media/openttd.64.xpm new file mode 100644 index 0000000..879bfe6 --- /dev/null +++ b/media/openttd.64.xpm @@ -0,0 +1,319 @@ +/* XPM */ +static char * openttd_64_xpm[] = { +"64 64 252 2", +" c None", +". c #212429", +"+ c #030006", +"@ c #402F20", +"# c #80582F", +"$ c #000100", +"% c #252B31", +"& c #2B1C0D", +"* c #DC9C55", +"= c #FFC36A", +"- c #1F180E", +"; c #D09351", +"> c #FEBA6A", +", c #ECAB62", +"' c #7E5935", +") c #F1AE5F", +"! c #F8AE62", +"~ c #2E3339", +"{ c #6F4B28", +"] c #150D04", +"^ c #C3884C", +"/ c #F4AB5F", +"( c #684B2B", +"_ c #353B3E", +": c #11100E", +"< c #FCB265", +"[ c #5D4327", +"} c #BA8144", +"| c #E9A863", +"1 c #E2A15A", +"2 c #563B1E", +"3 c #AC7A45", +"4 c #694D32", +"5 c #383937", +"6 c #929492", +"7 c #A5A8A8", +"8 c #9B9E9D", +"9 c #665D51", +"0 c #49321A", +"a c #3E4144", +"b c #090F13", +"c c #D5DADD", +"d c #E7EDEF", +"e c #F9FBF8", +"f c #988E82", +"g c #0A0201", +"h c #A2703D", +"i c #D9DBD7", +"j c #F6F8F5", +"k c #9A8A78", +"l c #916333", +"m c #5D5449", +"n c #F1F3F0", +"o c #EAA859", +"p c #4B4D4F", +"q c #9A6B37", +"r c #696762", +"s c #DFE1DE", +"t c #EFF1EE", +"u c #917E6B", +"v c #332312", +"w c #936D47", +"x c #563E28", +"y c #4F4842", +"z c #767470", +"A c #B1B3B0", +"B c #CDD1D0", +"C c #E9EBE7", +"D c #F3F5F2", +"E c #C0C2BF", +"F c #6F6051", +"G c #635345", +"H c #FFB25F", +"I c #050A06", +"J c #664220", +"K c #403A34", +"L c #858886", +"M c #C2C8CC", +"N c #EDEFEC", +"O c #DFE5E7", +"P c #797064", +"Q c #A8A29B", +"R c #BE8953", +"S c #ADB3B7", +"T c #E5E7E4", +"U c #9F7E5E", +"V c #F4A554", +"W c #F3A956", +"X c #D98F46", +"Y c #443D37", +"Z c #B1B0A7", +"` c #FDFFFC", +" . c #927960", +".. c #FFA652", +"+. c #FBAA59", +"@. c #11181E", +"#. c #C9C5BD", +"$. c #A89E91", +"%. c #F6A052", +"&. c #FBA950", +"*. c #1A0B00", +"=. c #AC783D", +"-. c #A68666", +";. c #7E6C5D", +">. c #BB7B44", +",. c #F69F4A", +"'. c #F79A48", +"). c #FFA349", +"!. c #845728", +"~. c #FDC880", +"{. c #C3813D", +"]. c #9E7047", +"^. c #F5983F", +"/. c #D07D2D", +"(. c #7A5028", +"_. c #817E79", +":. c #85705A", +"<. c #CA8136", +"[. c #985A22", +"}. c #98908A", +"|. c #8B6C50", +"1. c #F9953F", +"2. c #C77228", +"3. c #D1D1C8", +"4. c #F39A4E", +"5. c #FF9C3D", +"6. c #F98F34", +"7. c #F79335", +"8. c #945A2A", +"9. c #C17A3D", +"0. c #EE8C36", +"a. c #ED8632", +"b. c #E8903D", +"c. c #654B35", +"d. c #B36420", +"e. c #FF9030", +"f. c #FB8B33", +"g. c #FB8A29", +"h. c #C06B20", +"i. c #884914", +"j. c #DD863C", +"k. c #FB8427", +"l. c #FD8E23", +"m. c #B15B11", +"n. c #E78024", +"o. c #FC841D", +"p. c #F37E13", +"q. c #F89A41", +"r. c #D77921", +"s. c #655340", +"t. c #FE801C", +"u. c #FE7F0C", +"v. c #FE7A08", +"w. c #FF8814", +"x. c #C4600D", +"y. c #FF8700", +"z. c #4E2505", +"A. c #000205", +"B. c #745C46", +"C. c #DF7216", +"D. c #F2760D", +"E. c #FE7404", +"F. c #FF8000", +"G. c #974600", +"H. c #7A3F12", +"I. c #593513", +"J. c #513D2D", +"K. c #6A421A", +"L. c #9C520F", +"M. c #F67300", +"N. c #3E210D", +"O. c #BBC0C3", +"P. c #CE6000", +"Q. c #E86E00", +"R. c #FF7500", +"S. c #FF7B00", +"T. c #A14800", +"U. c #7A3601", +"V. c #1E3E10", +"W. c #352A35", +"X. c #122509", +"Y. c #3A7E1E", +"Z. c #813A00", +"`. c #8B8074", +" + c #C25600", +".+ c #A1836B", +"++ c #F46B00", +"@+ c #B57031", +"#+ c #AD5000", +"$+ c #1A3710", +"%+ c #62C52C", +"&+ c #61CC34", +"*+ c #382D38", +"=+ c #0B1A07", +"-+ c #5BB92A", +";+ c #6DE73A", +">+ c #4A9222", +",+ c #D05B00", +"'+ c #DF5F00", +")+ c #662E00", +"!+ c #55B32E", +"~+ c #6AD432", +"{+ c #69DC39", +"]+ c #1D380B", +"^+ c #0A1608", +"/+ c #72E236", +"(+ c #438D24", +"_+ c #752500", +":+ c #A64002", +"<+ c #BC5700", +"[+ c #17320B", +"}+ c #57AC28", +"|+ c #42861D", +"1+ c #5A2900", +"2+ c #152C0C", +"3+ c #0A1104", +"4+ c #100001", +"5+ c #469724", +"6+ c #73F43D", +"7+ c #234912", +"8+ c #2E5F18", +"9+ c #50AF29", +"0+ c #6EDE32", +"a+ c #295914", +"b+ c #5CC132", +"c+ c #255114", +"d+ c #38761E", +"e+ c #3F8222", +"f+ c #52A025", +"g+ c #6F2F00", +"h+ c #894000", +"i+ c #377019", +"j+ c #7DFF3F", +"k+ c #346A1C", +"l+ c #C96E14", +"m+ c #FF7004", +"n+ c #0B200A", +"o+ c #74EC36", +"p+ c #7C4A1D", +"q+ c #DE6701", +"r+ c #210901", +"s+ c #20440F", +"t+ c #4EA529", +"u+ c #8C3D00", +"v+ c #4D9C27", +"w+ c #66CF2D", +"x+ c #C55301", +"y+ c #2C0F00", +"z+ c #142806", +"A+ c #361500", +"B+ c #421C02", +"C+ c #3E7A1A", +" ", +" . + ", +" . @ # $ ", +" % & * = # $ ", +" % - ; > , > ' $ ", +" % - ; > , ) ! > ' $ ", +" ~ - ; > ! ! , ) ) > { $ ", +" ~ ] ^ > ! , , ! / , ! > ( $ ", +" _ : ^ > , ! ! , / ! , , > < ( $ ", +" ~ : ; > , ! , , < , / ! / / > < [ $ ", +" _ : } > , , ! ! | 1 1 , ) , , , ) < 2 $ ", +" _ : 3 = , , < , * 4 [ 4 ( 3 < / , ! > , 2 $ ", +" _ : } > / ! , ! , } 5 6 7 8 9 | < , , ) ) < 0 $ ", +" a b 3 > ! , | ! , < ^ 9 c d e f | ) ! , ! , > , 0 $ ", +" a g h > , ! ! , , > > } 9 i j e k | , ! , ! ! / > / @ $ ", +" a + h > , ! , , < ! , * l m i n e k | ! ! < > , , , > o @ $ ", +" p b q = , , ! < , 1 h { [ @ r s t e u ; > ; # # 3 ! , ! > | v $ ", +" p b w > / ! ! ) | q x y z 8 A B C t D E F # 2 p z G 1 ! , / H 1 v $ ", +" p I l > , , , < * J K L M i C C C C n N D O 6 P M d Q R < ) ) / < * & $ ", +" p b # > , , ! < | ( a S i N n n n D n t C t n n T C e B U < V V V W H X & $ ", +" p b # > ) < , , ) q Y Z s C n t e ` j t n n n n t N N t C ./ V / V ..V +.X - $ ", +" @.b # > , ! , ! < 1 x L i n n n D #.u $.e C C D ` C n C t e f * V %.%.V %.&...X *.$ ", +" @.b { > > , ! , , < =.y M N t C e Q -.^ ;.C D e k Q ` n n t e Q >...,.,.,.,.,.'.).X ] $ ", +" @.b { > ) , , , / ! ) !.z i t n j s U ~.{.9 i t j u !.f j t n e B ].&.'.'.'.'.'.^.'.)./.] $ ", +" @.@.( > < / ! / , , / / (._.C n t n C :.V <.G i n j k %.[.}.j t D N |.,.'.^.'.^.1.^.1.1.).2.] $ ", +" @.: 2 > ! / / / / / +.V +.(.}.C C t t ` Z ' [.9 3.n e u 4.5.(.E D n ` $.X 1.^.1.1.1.6.7.1.6.5.2.g $ ", +" @.@.2 H W / V V V V V V V &.8._.C D C n n e E G P T t e k ,.5./.F n j i _.9.6.7.6.0.1.a.6.6.6.6.5.2.g $ ", +" @.@.2 +.+./ V V V %.%.V %.,.V b.c.i D t t t N D d i C t j :.d.0.5.[._.u U R '.6.1.6.6.e.6.f.f.6.f.g.e.h.g $ ", +" @.@.0 +.+.%.V V %.V ,.%.,.%.,.,...8.Q j t C n t t n N C t D #.z [ i.2.j.4...1.6.g.6.f.6.g.g.g.f.g.k.g.g.l.m.g $ ", +" @.@.0 ..&.%.,.4.,.%.,.,.'.,.,.'.'.^.b.4 3.` n n C t t t n t t j D B 8 F i.n.e.k.f.f.f.g.k.f.g.g.o.o.o.o.p.o.l.m.g $ ", +" @.. 0 &...,.%.,.'.,.'.'.'.'.^.^.^.^.q.1.r.s.B ` D n t t C n t t t t N t d 7 c.h.e.g.k.g.g.o.k.k.o.k.o.t.u.t.v.u.w.m.] $ ", +" % g j.&.'.,.^.'.,.'.'.'.^.1.1.1.1.1.7.1.5.n.# 6 C ` j n n t t t t t t t N D O F x.l.o.t.t.t.t.u.t.u.t.t.u.v.u.u.v.y.z.A. ", +" A.& j.).'.'.1.1.0.^.1.^.1.0.1.6.1.e.7.a.r.n.d.|.f i e e C n t t t t t t N e d B.C.o.p.t.u.D.v.D.v.v.v.v.v.E.v.F.G.g A. ", +" g v b.q.0.^.1.5.a.7.6.7.6.6.6.a.d.H.I.J.K.e.k.2.8. .#.j t t D n t t t t N e M L.u.v.u.t.u.v.v.v.M.E.v.E.M.F.G.A.A. ", +" A.N.^.6.7.a.7.1.6.6.6.6.6.e.h.@ r 6 O.6 d.g.g.l.P.:.C t t C e e t t t t N ` :.Q.v.E.E.v.R.E.R.v.E.E.R.F.G.+ A. ", +" A.N.1.6.6.f.g.f.f.f.g.f.f.C.c.M N t O |.k.o.o.P.G i t e .:.3.e t t t n ` 7 x.v.S.v.E.R.R.R.E.R.S.F.T.A.$ ", +" . $ N.6.e.f.g.g.g.f.o.k.k.k.K.S n D e A L.w.w.P.s.i t e U C.U.#.D C n t e M d.F.E.E.R.S.R.R.R.R.F.T.A.V.V.$ ", +" W.X.Y.g N.6.l.g.k.k.p.k.o.w.t.Z.Q n t t D `. +u. +G i n D .+D.++J s n n C j M @+u.E.R.S.R.S.R.S.F.#+I $+%+&+V.$ ", +" *+=+-+;+>+g z.k.o.p.t.u.t.t.u.u.G._.t t t n d B.,+'+s.i n e .+D.++)+O.t n t ` A d.u.M.R.R.R.S.R.F.#+A.$+!+~+{+~+]+$ ", +" *+^+-+/+~+~+(++ z.w.o.u.t.t.v.u.t. +F C n t t j O B._+c.i n j U D.:+J.#.t n t ` k n.R.R.R.R.R.R.F.<+$ [+!+~+&+~+{+~+]+$ ", +" ~ =+}+/+~+{+~+/+|+A.1+u.u.v.M.v.v.v.,+c.s n t C D j d _.`.i n ` |.)+@ 6 i C n j O ].l.E.R.S.R.R.F.<+g 2+-+&+~+~+{+&+;+&+3+$ ", +"a 4+5+6+~+~+~+{+7+8+(+A.1+F.v.v.E.R.E.++K.#.n n n t t N t T C t D #.7 E i N n n e f j.S.E.M.R.M.F. ++ [+9+&+{+~+{+~+0+{+a+I @. ", +" + 2+b+{+{+/+c+V.]+d+e++ )+v.v.R.R.E.E.U.S t n n e D t t N t C t j N C t t D ` Q >.w.E.R.R.R.F.P.g $+d+$+2+f+/+~+~+/+8++ A. ", +" b X.&+/+c+V.{+~+I >+e++ g+S.S.S.S.E.h+}.t ` u u T ` D n t n t t n n D ` C }.>.g.E.R.R.R.F.P.g 2+d+=+!+f+=+}+{+/+8++ $ ", +" + 2+&+X.i+j+k+V.{+~+i+A.g+S.R.E.v.T.z ` i h l+(.Q T e C n C e ` ` T A |.9.w.m+R.R.S.F.P.*.n+!+f+3+!+j+i+d+j+k+g A. ", +" g $+&+$+2+V.o+-+3+Y.e+g U.F.v.E.'+{ `.P j.w.M.<+p+$.e n j 3.$.k w d.l.F.E.E.R.S.S.,+*.n+5+&+/+f+=+e+[+b+i++ A. ", +" g V.-+8+0+b+^+e+[+|+k+$ U.F.S.E.v.k.f.t.m+R.S.'+B.N t j .9.n.o.u.R.E.R.S.R.F.q+r+n+e+[+!+{+o+>+=+!+e+g $ ", +" + V./+&+=+3+f+}+A.&+d+$ Z.S.v.R.R.E.E.E.S.S.,+G 3.n j .+u.m+E.E.R.R.M.R.S.q+*.=+e+3+V.6+~+~+{+0+e++ $ ", +" + s+!+f+%+n+=+t+b+5+k+I u+F.S.S.R.S.R.R.S.,+G i D e .+D.E.v.R.R.R.R.F.Q.r+3+t+c+e+V.i+/+~+;+e++ $ ", +" + 7+;+;+}+v+w+X.=+>+k+A.h+F.R.S.R.R.S.S.x+G T ` ` .+p.R.R.M.S.R.S.Q.y+^+(+&+~+;+~+2+e+o+e++ $ ", +" + 7+{+;+&+2+3+e+z+(+8+g G.F.R.R.R.R.M.,+J.S O.M :.o.R.R.R.R.F.Q.y+^+|+V.!+/+~+{+b+>+>+b $ ", +" + 7+o+$+c+%+z+k+v+/+c+A.T.F.S.R.R.R.E.x.d.@+9.j.u.E.R.R.F.M.A+I e+=+s+o+~+~+~+o+>++ g ", +" + 8+}+n+}+!+v+{+[+5+a+$ T.F.S.R.R.R.S.F.w.w.v.E.R.R.S.Q.A+A.5+a+8+$+(+/+~+;+>+b $ ", +" g i+}+n+~+{+2+8+X.t+c+$ #+F.S.R.R.R.v.E.E.v.R.S.S.M.B+$ |+&+&+/+b+n+(+6+>++ $ ", +" I k+~+b+z+d+j+(+I b+7+A.#+F.S.R.E.E.E.E.R.R.S.M.B+$ e+&+&+{+~+/+!+v+t+: I ", +" g i+!+e+;+~+[+e+0+&+V.g #+F.S.R.v.E.R.S.S.D.z.g e+&+~+~+~+{+~+o+}+I $ ", +" g i+6+%+2+C+;+~+{+&+n+g <+F.R.R.R.R.S.M.z.A.I c+~+0+~+~+~+/+t+: I ", +" + e+}+d+/+~+{+/+i+g + ] <+F.S.M.S.S.1+g + 8+{+~+{+/+}+: A. ", +" + d+6+~+~+;+i+A.$ A.g P.F.R.S.1++ + 8+/+;+!+3+A. ", +" + e+o+;+d++ A. $ g P.F.)+g b k+b+3+A. ", +" + e+(+b $ g *.1+A. + + + ", +" g + g $ A. I ", +" $ ", +" "}; diff --git a/media/openttd.desktop b/media/openttd.desktop new file mode 100644 index 0000000..be68503 --- /dev/null +++ b/media/openttd.desktop @@ -0,0 +1,12 @@ +# $Id$ +# http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html +[Desktop Entry] +Type=Application +Version=1.0 +Name=OpenTTD +Icon=openttd +Exec=openttd +Terminal=false +Categories=Game; +Comment=A clone of Transport Tycoon Deluxe +Keywords=game;simulation;transport;tycoon;deluxe;economics;multiplayer;money;train;ship;bus;truck;aircraft;cargo; diff --git a/media/openttd.desktop.filter.awk b/media/openttd.desktop.filter.awk new file mode 100644 index 0000000..06cf110 --- /dev/null +++ b/media/openttd.desktop.filter.awk @@ -0,0 +1,13 @@ +# $Id: openttd.desktop.translation.awk 19884 2010-05-22 19:59:37Z rubidium $ + +# This file is part of OpenTTD. +# OpenTTD 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, version 2. +# OpenTTD 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 OpenTTD. If not, see . + +# +# Awk script to automatically remove duplicate Comment[i]= lines +# + +BEGIN { FS = "="; last = "" } +{ if (last != $1) { print $0 }; last = $1 } diff --git a/media/openttd.desktop.in b/media/openttd.desktop.in new file mode 100644 index 0000000..513ff71 --- /dev/null +++ b/media/openttd.desktop.in @@ -0,0 +1,12 @@ +# $Id$ +# http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html +[Desktop Entry] +Type=Application +Version=1.0 +Name=!!MENU_NAME!! +Icon=!!TTD!! +Exec=!!TTD!! +Terminal=false +Categories=!!MENU_GROUP!! +Comment=A clone of Transport Tycoon Deluxe +Keywords=game;simulation;transport;tycoon;deluxe;economics;multiplayer;money;train;ship;bus;truck;aircraft;cargo; diff --git a/media/openttd.desktop.install b/media/openttd.desktop.install new file mode 100644 index 0000000..b5850b8 --- /dev/null +++ b/media/openttd.desktop.install @@ -0,0 +1,118 @@ +# $Id$ +# http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html +[Desktop Entry] +Type=Application +Version=1.0 +Name=OpenTTD +Icon=openttd +Exec=openttd +Terminal=false +Categories=Game; +Comment=A clone of Transport Tycoon Deluxe +Keywords=game;simulation;transport;tycoon;deluxe;economics;multiplayer;money;train;ship;bus;truck;aircraft;cargo; +Comment[af]='n Simulasie speletjie wat gebaseer is op Transport Tycoon Deluxe +Comment[af_ZA]='n Simulasie speletjie wat gebaseer is op Transport Tycoon Deluxe +Comment[ar]=نسخة مستنسخة من ترانسبورت تايكون ديلوكس +Comment[ar_EG]=نسخة مستنسخة من ترانسبورت تايكون ديلوكس +Comment[be]=Эканамічны ÑімулÑтар на аÑнове «Transport Tycoon Deluxe» +Comment[be_BY]=Эканамічны ÑімулÑтар на аÑнове «Transport Tycoon Deluxe» +Comment[bg]=Симулативна игра, базирана на Transport Tycoon Deluxe +Comment[bg_BG]=Симулативна игра, базирана на Transport Tycoon Deluxe +Comment[ca]=Un joc de simulació basat en Transport Tycoon Deluxe +Comment[ca_ES]=Un joc de simulació basat en Transport Tycoon Deluxe +Comment[cs]=SimulaÄní hra založená na Transport Tycoon Deluxe +Comment[cs_CZ]=SimulaÄní hra založená na Transport Tycoon Deluxe +Comment[cy]=Gêm efelychu wedi ei seilio ar Transport Tycoon Deluxe +Comment[cy_GB]=Gêm efelychu wedi ei seilio ar Transport Tycoon Deluxe +Comment[da]=Et simulationsspil baseret pÃ¥ Transport Tycoon Deluxe +Comment[da_DK]=Et simulationsspil baseret pÃ¥ Transport Tycoon Deluxe +Comment[de]=Ein auf der Idee von Transport Tycoon Deluxe basierendes Spiel +Comment[de_DE]=Ein auf der Idee von Transport Tycoon Deluxe basierendes Spiel +Comment[el]=Ένα παιχνίδι εξομοίωσης βασισμένο στο Transport Tycoon Deluxe +Comment[el_GR]=Ένα παιχνίδι εξομοίωσης βασισμένο στο Transport Tycoon Deluxe +Comment[en]=A simulation game based on Transport Tycoon Deluxe +Comment[en_AU]=A simulation game based on Transport Tycoon Deluxe +Comment[en_GB]=A simulation game based on Transport Tycoon Deluxe +Comment[en_US]=A simulation game based on Transport Tycoon Deluxe +Comment[eo]=Al simulado ludo bazita sur Transport Tycoon Deluxe +Comment[eo_EO]=Al simulado ludo bazita sur Transport Tycoon Deluxe +Comment[es]=Un juego de simulación basado en Transport Tycoon Deluxe +Comment[es_ES]=Un juego de simulación basado en Transport Tycoon Deluxe +Comment[et]=Transport Tycoon Deluxe'il põhinev simulatsioonimäng +Comment[et_EE]=Transport Tycoon Deluxe'il põhinev simulatsioonimäng +Comment[eu]=Transport Tycoon Deluxe-ren simulazio bat +Comment[eu_ES]=Transport Tycoon Deluxe-ren simulazio bat +Comment[fi]=Transport Tycoon Deluxeen pohjautuva simulaatiopeli +Comment[fi_FI]=Transport Tycoon Deluxeen pohjautuva simulaatiopeli +Comment[fo]=Eitt eftirgerðar spæl bygt á Transport Tycoon Deluxe +Comment[fo_FO]=Eitt eftirgerðar spæl bygt á Transport Tycoon Deluxe +Comment[fr]=Un jeu de simulation basé sur Transport Tycoon Deluxe +Comment[fr_FR]=Un jeu de simulation basé sur Transport Tycoon Deluxe +Comment[ga]=Cluiche ionsamhlúcháin bunaithe ar Transport Tycoon Deluxe +Comment[ga_IE]=Cluiche ionsamhlúcháin bunaithe ar Transport Tycoon Deluxe +Comment[gd]=Geama saoghail mas-fhìor stèidhichte air Transport Tycoon Deluxe +Comment[gd_GB]=Geama saoghail mas-fhìor stèidhichte air Transport Tycoon Deluxe +Comment[gl]=Xogo de simulación baseado en Transport Tycoon Deluxe +Comment[gl_ES]=Xogo de simulación baseado en Transport Tycoon Deluxe +Comment[he]=משחק סימולציה המבוסס על תחבורה, הון ופ×ר +Comment[he_IL]=משחק סימולציה המבוסס על תחבורה, הון ופ×ר +Comment[hr]=Simulacija na osnovi Transport Tycoon Deluxea +Comment[hr_HR]=Simulacija na osnovi Transport Tycoon Deluxea +Comment[hu]=Transport Tycoon Deluxe alapokon nyugvó szimulációs játék +Comment[hu_HU]=Transport Tycoon Deluxe alapokon nyugvó szimulációs játék +Comment[id]=Permainan simulasi berdasarkan Transport Tycoon Deluxe +Comment[id_ID]=Permainan simulasi berdasarkan Transport Tycoon Deluxe +Comment[is]=Transport Tycoon Deluxe eftirherma +Comment[is_IS]=Transport Tycoon Deluxe eftirherma +Comment[it]=Gioco di simulazione basato su Transport Tycoon Deluxe +Comment[it_IT]=Gioco di simulazione basato su Transport Tycoon Deluxe +Comment[ja]=Transport Tycoon Deluxeを基ã«ã—ãŸã‚·ãƒŸãƒ¥ãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³ã‚²ãƒ¼ãƒ  +Comment[ja_JP]=Transport Tycoon Deluxeを基ã«ã—ãŸã‚·ãƒŸãƒ¥ãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³ã‚²ãƒ¼ãƒ  +Comment[ko]=트랜스í¬íЏ 타ì´ì¿¤ 디럭스를 기반으로 한 시뮬레ì´ì…˜ 게임입니다. +Comment[ko_KR]=트랜스í¬íЏ 타ì´ì¿¤ 디럭스를 기반으로 한 시뮬레ì´ì…˜ 게임입니다. +Comment[la]=Ludus computatralis simulatorius cuius fundamentum est Transport Tycoon Deluxe +Comment[la_VA]=Ludus computatralis simulatorius cuius fundamentum est Transport Tycoon Deluxe +Comment[lb]=Eng Simulatioun déi op Transport Tycoon Deluxe baséiert +Comment[lb_LU]=Eng Simulatioun déi op Transport Tycoon Deluxe baséiert +Comment[lt]=Simuliatoriaus žaidimas kurtas pagal Transport Tycoon Deluxe +Comment[lt_LT]=Simuliatoriaus žaidimas kurtas pagal Transport Tycoon Deluxe +Comment[lv]=Uz 'Transport Tycoon Deluxe' balstÄ«ta simulÄcijas spÄ“le +Comment[lv_LV]=Uz 'Transport Tycoon Deluxe' balstÄ«ta simulÄcijas spÄ“le +Comment[ms]=Sebuah permainan simulasi berasaskan Transport Tycoon Deluxe +Comment[ms_MY]=Sebuah permainan simulasi berasaskan Transport Tycoon Deluxe +Comment[nb]=Et simuleringsspill basert pÃ¥ Transport Tycoon Deluxe +Comment[nb_NO]=Et simuleringsspill basert pÃ¥ Transport Tycoon Deluxe +Comment[nl]=Een simulatiespel gebaseerd op Transport Tycoon Deluxe +Comment[nl_NL]=Een simulatiespel gebaseerd op Transport Tycoon Deluxe +Comment[nn]=Eit simulatorspel basert pÃ¥ Transport Tycoon Deluxe +Comment[nn_NO]=Eit simulatorspel basert pÃ¥ Transport Tycoon Deluxe +Comment[pl]=Gra symulacyjna oparta na Transport Tycoon Deluxe +Comment[pl_PL]=Gra symulacyjna oparta na Transport Tycoon Deluxe +Comment[pt]=Um jogo de simulação baseado no Transport Tycoon Deluxe +Comment[pt_BR]=Um jogo de simulação baseado no Transport Tycoon Deluxe +Comment[pt_PT]=Um jogo de simulação baseado no Transport Tycoon Deluxe +Comment[ro]=Un joc de simulare bazat pe Transport Tycoon Deluxe +Comment[ro_RO]=Un joc de simulare bazat pe Transport Tycoon Deluxe +Comment[ru]=ЭкономичеÑкий ÑимулÑтор на оÑнове игры «Transport Tycoon Deluxe» +Comment[ru_RU]=ЭкономичеÑкий ÑимулÑтор на оÑнове игры «Transport Tycoon Deluxe» +Comment[sk]=Simulátor založený na hre Transport Tycoon Deluxe +Comment[sk_SK]=Simulátor založený na hre Transport Tycoon Deluxe +Comment[sl]=Simulacija, temeljeÄa na Transport Tycoonu Deluxe +Comment[sl_SI]=Simulacija, temeljeÄa na Transport Tycoonu Deluxe +Comment[sr]=Simulacija bazirana na igri Transport Tycoon Deluxe +Comment[sr_RS]=Simulacija bazirana na igri Transport Tycoon Deluxe +Comment[sv]=Ett simuleringsspel baserat pÃ¥ Transport Tycoon Deluxe +Comment[sv_SE]=Ett simuleringsspel baserat pÃ¥ Transport Tycoon Deluxe +Comment[ta]=A simulation game based on Transport Tycoon Deluxe +Comment[ta_IN]=A simulation game based on Transport Tycoon Deluxe +Comment[th]=เป็นเà¸à¸¡à¸§à¸²à¸‡à¹à¸œà¸™à¹à¸¥à¸°à¸ˆà¸³à¸¥à¸­à¸‡ ซึ่งมีต้นฉบับมาจาภTransport Tycoon Deluxe +Comment[th_TH]=เป็นเà¸à¸¡à¸§à¸²à¸‡à¹à¸œà¸™à¹à¸¥à¸°à¸ˆà¸³à¸¥à¸­à¸‡ ซึ่งมีต้นฉบับมาจาภTransport Tycoon Deluxe +Comment[tr]=Transport Tycoon Deluxe'ü temel alan bir simülasyon oyunu +Comment[tr_TR]=Transport Tycoon Deluxe'ü temel alan bir simülasyon oyunu +Comment[uk]=Гра-ÑимулÑтор, заÑнована на Transport Tycoon Deluxe +Comment[uk_UA]=Гра-ÑимулÑтор, заÑнована на Transport Tycoon Deluxe +Comment[vi]=Má»™t trò chÆ¡i mô phá»ng dá»±a trên Transport Tycoon Deluxe +Comment[vi_VN]=Má»™t trò chÆ¡i mô phá»ng dá»±a trên Transport Tycoon Deluxe +Comment[zh]=基于Transport Tycoon Deluxe(è¿è¾“大亨豪åŽç‰ˆï¼‰çš„æ¨¡æ‹Ÿè¿è¥æ¸¸æˆ +Comment[zh_CN]=基于Transport Tycoon Deluxe(è¿è¾“大亨豪åŽç‰ˆï¼‰çš„æ¨¡æ‹Ÿè¿è¥æ¸¸æˆ +Comment[zh_TW]=基於《é‹è¼¸å¤§äº¨è±ªè¯ç‰ˆã€‹çš„é‹è¼¸æ¨¡æ“¬éŠæˆ² diff --git a/media/openttd.desktop.translation.awk b/media/openttd.desktop.translation.awk new file mode 100644 index 0000000..ee8fdd9 --- /dev/null +++ b/media/openttd.desktop.translation.awk @@ -0,0 +1,15 @@ +# $Id$ + +# This file is part of OpenTTD. +# OpenTTD 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, version 2. +# OpenTTD 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 OpenTTD. If not, see . + +# +# Awk script to automatically generate a comment lines for +# a translated desktop shortcut. If it does not exist there +# is no output. +# + +/##isocode/ { lang = $2; next } +/STR_DESKTOP_SHORTCUT_COMMENT/ { sub("^[^:]*:", "", $0); print "Comment[" lang "]=" $0; sub("_.*", "", lang); print "Comment[" lang "]=" $0; next} diff --git a/media/openttd.ico b/media/openttd.ico new file mode 100644 index 0000000..b2b12ca Binary files /dev/null and b/media/openttd.ico differ diff --git a/media/openttd.svg b/media/openttd.svg new file mode 100644 index 0000000..30aba23 --- /dev/null +++ b/media/openttd.svg @@ -0,0 +1,265 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/objs/extra_grf/Makefile b/objs/extra_grf/Makefile new file mode 100644 index 0000000..fcd6245 --- /dev/null +++ b/objs/extra_grf/Makefile @@ -0,0 +1,96 @@ +# Auto-generated file from 'Makefile.grf.in' -- DO NOT EDIT +# $Id$ + +# This file is part of OpenTTD. +# OpenTTD 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, version 2. +# OpenTTD 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 OpenTTD. If not, see . +# +# Building requires GRFCodec and NFORenum. Older versions of GRFCodec are +# known to miscompile the graphics. +# +# Recent nightlies (including sources) of both can be found at: +# http://www.openttd.org/download-grfcodec +# http://www.openttd.org/download-nforenum +# +# The mercurial repository of both can be found at: +# http://hg.openttdcoop.org/grfcodec +# http://hg.openttdcoop.org/nforenum +# + + +ROOT_DIR = /home/openttd/openttd-virj-source +GRF_DIR = $(ROOT_DIR)/media/extra_grf +BASESET_DIR = $(ROOT_DIR)/media/baseset +LANG_DIR = $(ROOT_DIR)/src/lang +BIN_DIR = /home/openttd/openttd-virj-source/bin/baseset +OBJS_DIR = /home/openttd/openttd-virj-source/objs/extra_grf +OS = UNIX +STAGE = [BASESET] + +# Check if we want to show what we are doing +ifdef VERBOSE + Q = + E = @true +else + Q = @ + E = @echo +endif + +GRFCODEC := +NFORENUM := +CC_BUILD := gcc +MD5SUM := $(shell [ "$(OS)" = "OSX" ] && echo "md5 -r" || echo "md5sum") + +# Some "should not be changed" settings. +NFO_FILES := $(GRF_DIR)/*.nfo $(GRF_DIR)/rivers/*.nfo +PNG_FILES := $(GRF_DIR)/*.png $(GRF_DIR)/rivers/*.png + +# Build the GRF. +ifdef GRFCODEC +all: $(BIN_DIR)/openttd.grf $(BIN_DIR)/orig_dos.obg $(BIN_DIR)/orig_dos_de.obg $(BIN_DIR)/orig_win.obg $(BIN_DIR)/orig_dos.obs $(BIN_DIR)/orig_win.obs $(BIN_DIR)/no_sound.obs $(BIN_DIR)/orig_win.obm $(BIN_DIR)/no_music.obm +else +all: +endif + +# Make sure the sprites directory exists. +$(OBJS_DIR)/sprites: + $(Q)-mkdir "$@" + +$(OBJS_DIR)/langfiles.tmp: $(LANG_DIR)/*.txt + $(E) '$(STAGE) Collecting baseset translations' + $(Q) cat $^ > $@ + +$(BIN_DIR)/%.obg: $(BASESET_DIR)/%.obg $(BIN_DIR)/openttd.grf $(OBJS_DIR)/langfiles.tmp $(BASESET_DIR)/translations.awk + $(E) '$(STAGE) Updating $(notdir $@)' + $(Q) sed 's/^OPENTTD.GRF = *[0-9a-f]*$$/OPENTTD.GRF = '`$(MD5SUM) $(BIN_DIR)/openttd.grf | sed 's@ .*@@'`'/' $< > $@.tmp + $(Q) awk -v langfiles='$(OBJS_DIR)/langfiles.tmp' -f $(BASESET_DIR)/translations.awk $@.tmp >$@ + $(Q) rm $@.tmp + +$(BIN_DIR)/%.obs: $(BASESET_DIR)/%.obs $(OBJS_DIR)/langfiles.tmp $(BASESET_DIR)/translations.awk + $(E) '$(STAGE) Updating $(notdir $@)' + $(Q) awk -v langfiles='$(OBJS_DIR)/langfiles.tmp' -f $(BASESET_DIR)/translations.awk $< >$@ + +$(BIN_DIR)/%.obm: $(BASESET_DIR)/%.obm $(OBJS_DIR)/langfiles.tmp $(BASESET_DIR)/translations.awk + $(E) '$(STAGE) Updating $(notdir $@)' + $(Q) awk -v langfiles='$(OBJS_DIR)/langfiles.tmp' -f $(BASESET_DIR)/translations.awk $< >$@ + +# Compile extra grf +$(BIN_DIR)/openttd.grf: $(PNG_FILES) $(NFO_FILES) $(OBJS_DIR)/sprites $(GRF_DIR)/assemble_nfo.awk + $(E) '$(STAGE) Assembling openttd.nfo' + $(Q)-cp $(PNG_FILES) $(OBJS_DIR)/sprites 2> /dev/null + $(Q) awk -f $(GRF_DIR)/assemble_nfo.awk $(GRF_DIR)/openttd.nfo > $(OBJS_DIR)/sprites/openttd.nfo + $(Q) $(NFORENUM) -s $(OBJS_DIR)/sprites/openttd.nfo + $(E) '$(STAGE) Compiling openttd.grf' + $(Q) $(GRFCODEC) -n -s -e -p1 $(OBJS_DIR)/openttd.grf + $(Q)cp $(OBJS_DIR)/openttd.grf $(BIN_DIR)/openttd.grf + +# Clean up temporary files. +clean: + $(Q)rm -f *.bak *.grf + +# Clean up temporary files +mrproper: clean + $(Q)rm -fr sprites + +.PHONY: all mrproper depend clean diff --git a/objs/lang/Makefile b/objs/lang/Makefile new file mode 100644 index 0000000..ff0aa79 --- /dev/null +++ b/objs/lang/Makefile @@ -0,0 +1,106 @@ +# Auto-generated file from 'Makefile.lang.in' -- DO NOT EDIT +# $Id$ + +# This file is part of OpenTTD. +# OpenTTD 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, version 2. +# OpenTTD 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 OpenTTD. If not, see . + +STRGEN = strgen +ENDIAN_CHECK = endian_check +SRC_DIR = /home/openttd/openttd-virj-source/src +LANG_DIR = /home/openttd/openttd-virj-source/src/lang +BIN_DIR = /home/openttd/openttd-virj-source/bin +LANGS_SRC = $(shell ls $(LANG_DIR)/*.txt) +LANGS = $(LANGS_SRC:$(LANG_DIR)/%.txt=%.lng) +CXX_BUILD = g++ +CFLAGS_BUILD = -Wall -Wno-multichar -Wsign-compare -Wundef -Wwrite-strings -Wpointer-arith -W -Wno-unused-parameter -Wredundant-decls -Wformat=2 -Wformat-security -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-but-set-parameter -Winit-self -fno-strict-aliasing -Wcast-qual -fno-strict-overflow -Wnon-virtual-dtor -Wno-free-nonheap-object -rdynamic -DUNIX -D_FORTIFY_SOURCE=2 -O1 -DNDEBUG +CXXFLAGS_BUILD= -std=gnu++0x -Wno-narrowing +LDFLAGS_BUILD = -rdynamic +STRGEN_FLAGS = +STAGE = [LANG] +LANG_SUPPRESS = +LANG_OBJS_DIR = /home/openttd/openttd-virj-source/objs/lang + +ifeq ($(LANG_SUPPRESS), yes) +LANG_ERRORS = >/dev/null 2>&1 +endif + +# Make sure endian_host.h is reachable as if it was in the src/ dir +CFLAGS_BUILD += -I $(LANG_OBJS_DIR) + +ENDIAN_TARGETS := endian_host.h endian_target.h $(ENDIAN_CHECK) + +# Check if we want to show what we are doing +ifdef VERBOSE + Q = + E = @true +else + Q = @ + E = @echo +endif + +RES := $(shell mkdir -p $(BIN_DIR)/lang ) + +all: table/strings.h $(LANGS) + +strgen_base.o: $(SRC_DIR)/strgen/strgen_base.cpp $(SRC_DIR)/strgen/strgen.h endian_host.h $(SRC_DIR)/table/control_codes.h $(SRC_DIR)/table/strgen_tables.h $(SRC_DIR)/safeguards.h + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSTRGEN -c -o $@ $< + +strgen.o: $(SRC_DIR)/strgen/strgen.cpp $(SRC_DIR)/strgen/strgen.h endian_host.h $(SRC_DIR)/table/control_codes.h $(SRC_DIR)/table/strgen_tables.h $(SRC_DIR)/safeguards.h + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSTRGEN -c -o $@ $< + +string.o: $(SRC_DIR)/string.cpp endian_host.h $(SRC_DIR)/safeguards.h + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSTRGEN -c -o $@ $< + +alloc_func.o: $(SRC_DIR)/core/alloc_func.cpp endian_host.h $(SRC_DIR)/safeguards.h + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSTRGEN -c -o $@ $< + +getoptdata.o: $(SRC_DIR)/misc/getoptdata.cpp $(SRC_DIR)/misc/getoptdata.h $(SRC_DIR)/safeguards.h + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/misc/%.cpp=%.cpp)' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSTRGEN -c -o $@ $< + +lang/english.txt: $(LANG_DIR)/english.txt + $(Q)mkdir -p lang + $(Q)cp $(LANG_DIR)/english.txt lang/english.txt + +$(STRGEN): alloc_func.o string.o strgen_base.o strgen.o getoptdata.o + $(E) '$(STAGE) Compiling and Linking $@' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) $(LDFLAGS_BUILD) $^ -o $@ + +table/strings.h: lang/english.txt $(STRGEN) + $(E) '$(STAGE) Generating $@' + @mkdir -p table + $(Q)./$(STRGEN) -s $(LANG_DIR) -d table + +$(LANGS): %.lng: $(LANG_DIR)/%.txt $(STRGEN) lang/english.txt + $(E) '$(STAGE) Compiling language $(*F)' + $(Q)./$(STRGEN) $(STRGEN_FLAGS) -s $(LANG_DIR) -d $(LANG_OBJS_DIR) $< $(LANG_ERRORS) && cp $@ $(BIN_DIR)/lang || true # Do not fail all languages when one fails + +# The targets to compile the endian-code + +endian_host.h: $(ENDIAN_CHECK) + $(E) '$(STAGE) Testing endianness for host' + $(Q)./$(ENDIAN_CHECK) > $@ + +$(ENDIAN_CHECK): $(SRC_DIR)/endian_check.cpp + $(E) '$(STAGE) Compiling and Linking $@' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) $(LDFLAGS_BUILD) $< -o $@ + +depend: + +clean: + $(E) '$(STAGE) Cleaning up language files' + $(Q)rm -f strgen.o string.o alloc_func.o getoptdata.o table/strings.h $(STRGEN) $(LANGS) $(LANGS:%=$(BIN_DIR)/lang/%) lang/english.* $(ENDIAN_TARGETS) + +mrproper: clean + $(Q)rm -rf $(BIN_DIR)/lang + +%.lng: + @echo '$(STAGE) No such language: $(@:%.lng=%)' + +.PHONY: all mrproper depend clean diff --git a/objs/lang/strgen_base.o b/objs/lang/strgen_base.o new file mode 100644 index 0000000..95130f9 Binary files /dev/null and b/objs/lang/strgen_base.o differ diff --git a/objs/release/Makefile b/objs/release/Makefile new file mode 100644 index 0000000..9dfc3ed --- /dev/null +++ b/objs/release/Makefile @@ -0,0 +1,316 @@ +# Auto-generated file from 'Makefile.src.in' -- DO NOT EDIT +# $Id$ + +# This file is part of OpenTTD. +# OpenTTD 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, version 2. +# OpenTTD 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 OpenTTD. If not, see . + +CC_HOST = gcc +CXX_HOST = g++ +CC_BUILD = gcc +CXX_BUILD = g++ +WINDRES = +STRIP = strip -s +CFLAGS = -O2 -fomit-frame-pointer -Wall -Wno-multichar -Wsign-compare -Wundef -Wwrite-strings -Wpointer-arith -W -Wno-unused-parameter -Wredundant-decls -Wformat=2 -Wformat-security -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-but-set-parameter -Winit-self -fno-strict-aliasing -Wcast-qual -fno-strict-overflow -Wnon-virtual-dtor -Wno-free-nonheap-object -rdynamic -DUNIX -D_FORTIFY_SOURCE=2 -DWITH_SSE -DWITH_ZLIB -DWITH_LZMA -DWITH_LZO -D_SQ64 -I/home/openttd/openttd-virj-source/src/3rdparty/squirrel/include -DWITH_PNG -I/usr/include/libpng12 -DDEDICATED -DENABLE_NETWORK -DNDEBUG -DWITH_PERSONAL_DIR -DPERSONAL_DIR=\".openttd\" -DGLOBAL_DATA_DIR=\"/usr/local/share/games/openttd\" +CFLAGS_BUILD = -Wall -Wno-multichar -Wsign-compare -Wundef -Wwrite-strings -Wpointer-arith -W -Wno-unused-parameter -Wredundant-decls -Wformat=2 -Wformat-security -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-but-set-parameter -Winit-self -fno-strict-aliasing -Wcast-qual -fno-strict-overflow -Wnon-virtual-dtor -Wno-free-nonheap-object -rdynamic -DUNIX -D_FORTIFY_SOURCE=2 -O1 -DNDEBUG +CXXFLAGS = -std=gnu++0x -Wno-narrowing +CXXFLAGS_BUILD = -std=gnu++0x -Wno-narrowing +LIBS = -lstdc++ -lpthread -lc -lz -llzma -llzo2 -lpng12 +LDFLAGS = -rdynamic +LDFLAGS_BUILD = -rdynamic +ROOT_DIR = /home/openttd/openttd-virj-source +BIN_DIR = /home/openttd/openttd-virj-source/bin +LANG_DIR = /home/openttd/openttd-virj-source/src/lang +SRC_OBJS_DIR = /home/openttd/openttd-virj-source/objs/release +LANG_OBJS_DIR = /home/openttd/openttd-virj-source/objs/lang +SETTING_OBJS_DIR= /home/openttd/openttd-virj-source/objs/setting +SRC_DIR = /home/openttd/openttd-virj-source/src +SCRIPT_SRC_DIR = /home/openttd/openttd-virj-source/src/3rdparty/squirrel/include +MEDIA_DIR = /home/openttd/openttd-virj-source/media +TTD = openttd +STRGEN = strgen +ENDIAN_CHECK = endian_check +DEPEND = depend +ENDIAN_FORCE = AUTO +OS = UNIX +STAGE = [SRC] +MAKEDEPEND = $(SRC_OBJS_DIR)/$(DEPEND) +CFLAGS_MAKEDEP = -D__SSP_STRONG__ -D__DBL_MIN_EXP__ -D__cpp_attributes -D__UINT_LEAST16_MAX__ -D__ATOMIC_ACQUIRE -D__FLT_MIN__ -D__GCC_IEC_559_COMPLEX -D__UINT_LEAST8_TYPE__ -D__INTMAX_C -D__CHAR_BIT__ -D__UINT8_MAX__ -D__WINT_MAX__ -D__cpp_static_assert -D__ORDER_LITTLE_ENDIAN__ -D__SIZE_MAX__ -D__WCHAR_MAX__ -D__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 -D__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 -D__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 -D__DBL_DENORM_MIN__ -D__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 -D__GCC_ATOMIC_CHAR_LOCK_FREE -D__GCC_IEC_559 -D__FLT_EVAL_METHOD__ -D__unix__ -D__cpp_binary_literals -D__GCC_ATOMIC_CHAR32_T_LOCK_FREE -D__x86_64 -D__cpp_variadic_templates -D__UINT_FAST64_MAX__ -D__SIG_ATOMIC_TYPE__ -D__DBL_MIN_10_EXP__ -D__FINITE_MATH_ONLY__ -D__GNUC_PATCHLEVEL__ -D__UINT_FAST8_MAX__ -D__has_include -D__DEC64_MAX_EXP__ -D__INT8_C -D__UINT_LEAST64_MAX__ -D__SHRT_MAX__ -D__LDBL_MAX__ -D__UINT_LEAST8_MAX__ -D__GCC_ATOMIC_BOOL_LOCK_FREE -D__UINTMAX_TYPE__ -D__linux -D__DEC32_EPSILON__ -D__unix -D__UINT32_MAX__ -D__GXX_EXPERIMENTAL_CXX0X__ -D__LDBL_MAX_EXP__ -D__WINT_MIN__ -D__linux__ -D__SCHAR_MAX__ -D__WCHAR_MIN__ -D__INT64_C -D__DBL_DIG__ -D__GCC_ATOMIC_POINTER_LOCK_FREE -D__SIZEOF_INT__ -D__SIZEOF_POINTER__ -D__GCC_ATOMIC_CHAR16_T_LOCK_FREE -D__USER_LABEL_PREFIX__ -D__STDC_HOSTED__ -D__LDBL_HAS_INFINITY__ -D__FLT_EPSILON__ -D__GXX_WEAK__ -D__LDBL_MIN__ -D__DEC32_MAX__ -D__INT32_MAX__ -D__SIZEOF_LONG__ -D__STDC_IEC_559__ -D__STDC_ISO_10646__ -D__UINT16_C -D__DECIMAL_DIG__ -D__gnu_linux__ -D__has_include_next -D__LDBL_HAS_QUIET_NAN__ -D__GNUC__ -D__GXX_RTTI -D__MMX__ -D__FLT_HAS_DENORM__ -D__SIZEOF_LONG_DOUBLE__ -D__BIGGEST_ALIGNMENT__ -D__DBL_MAX__ -D__cpp_raw_strings -D__INT_FAST32_MAX__ -D__DBL_HAS_INFINITY__ -D__INT64_MAX__ -D__DEC32_MIN_EXP__ -D__INT_FAST16_TYPE__ -D__LDBL_HAS_DENORM__ -D__cplusplus -D__DEC128_MAX__ -D__INT_LEAST32_MAX__ -D__DEC32_MIN__ -D__DEPRECATED -D__DBL_MAX_EXP__ -D__DEC128_EPSILON__ -D__SSE2_MATH__ -D__ATOMIC_HLE_RELEASE -D__PTRDIFF_MAX__ -D__amd64 -D__STDC_NO_THREADS__ -D__ATOMIC_HLE_ACQUIRE -D__GNUG__ -D__LONG_LONG_MAX__ -D__SIZEOF_SIZE_T__ -D__cpp_rvalue_reference -D__SIZEOF_WINT_T__ -D__GCC_HAVE_DWARF2_CFI_ASM -D__GXX_ABI_VERSION -D__FLT_MIN_EXP__ -D__cpp_lambdas -D__INT_FAST64_TYPE__ -D__DBL_MIN__ -D__LP64__ -D__DECIMAL_BID_FORMAT__ -D__DEC128_MIN__ -D__REGISTER_PREFIX__ -D__UINT16_MAX__ -D__DBL_HAS_DENORM__ -D__UINT8_TYPE__ -D__NO_INLINE__ -D__FLT_MANT_DIG__ -D__VERSION__ -D__UINT64_C -D__cpp_unicode_characters -D_STDC_PREDEF_H -D__GCC_ATOMIC_INT_LOCK_FREE -D__FLOAT_WORD_ORDER__ -D__STDC_IEC_559_COMPLEX__ -D__INT32_C -D__DEC64_EPSILON__ -D__ORDER_PDP_ENDIAN__ -D__DEC128_MIN_EXP__ -D__INT_FAST32_TYPE__ -D__UINT_LEAST16_TYPE__ -Dunix -D__INT16_MAX__ -D__SIZE_TYPE__ -D__UINT64_MAX__ -D__INT8_TYPE__ -D__ELF__ -D__FLT_RADIX__ -D__INT_LEAST16_TYPE__ -D__LDBL_EPSILON__ -D__UINTMAX_C -D__k8 -D__SIG_ATOMIC_MAX__ -D__GCC_ATOMIC_WCHAR_T_LOCK_FREE -D__SIZEOF_PTRDIFF_T__ -D__x86_64__ -D__DEC32_SUBNORMAL_MIN__ -D__INT_FAST16_MAX__ -D__UINT_FAST32_MAX__ -D__UINT_LEAST64_TYPE__ -D__FLT_HAS_QUIET_NAN__ -D__FLT_MAX_10_EXP__ -D__LONG_MAX__ -D__DEC128_SUBNORMAL_MIN__ -D__FLT_HAS_INFINITY__ -D__cpp_unicode_literals -D__UINT_FAST16_TYPE__ -D__DEC64_MAX__ -D__CHAR16_TYPE__ -D__PRAGMA_REDEFINE_EXTNAME -D__INT_LEAST16_MAX__ -D__DEC64_MANT_DIG__ -D__UINT_LEAST32_MAX__ -D__GCC_ATOMIC_LONG_LOCK_FREE -D__INT_LEAST64_TYPE__ -D__INT16_TYPE__ -D__INT_LEAST8_TYPE__ -D__DEC32_MAX_EXP__ -D__INT_FAST8_MAX__ -D__INTPTR_MAX__ -Dlinux -D__SSE2__ -D__EXCEPTIONS -D__LDBL_MANT_DIG__ -D__DBL_HAS_QUIET_NAN__ -D__SIG_ATOMIC_MIN__ -D__code_model_small__ -D__k8__ -D__INTPTR_TYPE__ -D__UINT16_TYPE__ -D__WCHAR_TYPE__ -D__SIZEOF_FLOAT__ -D__UINTPTR_MAX__ -D__DEC64_MIN_EXP__ -D__cpp_decltype -D__INT_FAST64_MAX__ -D__GCC_ATOMIC_TEST_AND_SET_TRUEVAL -D__FLT_DIG__ -D__UINT_FAST64_TYPE__ -D__INT_MAX__ -D__amd64__ -D__INT64_TYPE__ -D__FLT_MAX_EXP__ -D__ORDER_BIG_ENDIAN__ -D__DBL_MANT_DIG__ -D__INT_LEAST64_MAX__ -D__DEC64_MIN__ -D__WINT_TYPE__ -D__UINT_LEAST32_TYPE__ -D__SIZEOF_SHORT__ -D__SSE__ -D__LDBL_MIN_EXP__ -D__INT_LEAST8_MAX__ -D__SIZEOF_INT128__ -D__LDBL_MAX_10_EXP__ -D__ATOMIC_RELAXED -D__DBL_EPSILON__ -D_LP64 -D__UINT8_C -D__INT_LEAST32_TYPE__ -D__SIZEOF_WCHAR_T__ -D__UINT64_TYPE__ -D__INT_FAST8_TYPE__ -D__GNUC_STDC_INLINE__ -D__DBL_DECIMAL_DIG__ -D__FXSR__ -D__DEC_EVAL_METHOD__ -D__UINT32_C -D__INTMAX_MAX__ -D__cpp_alias_templates -D__BYTE_ORDER__ -D__FLT_DENORM_MIN__ -D__INT8_MAX__ -D__UINT_FAST32_TYPE__ -D__CHAR32_TYPE__ -D__FLT_MAX__ -D__cpp_constexpr -D__INT32_TYPE__ -D__SIZEOF_DOUBLE__ -D__INTMAX_TYPE__ -D__DEC128_MAX_EXP__ -D__ATOMIC_CONSUME -D__GNUC_MINOR__ -D__UINTMAX_MAX__ -D__DEC32_MANT_DIG__ -D__DBL_MAX_10_EXP__ -D__LDBL_DENORM_MIN__ -D__INT16_C -D__STDC__ -D__PTRDIFF_TYPE__ -D__ATOMIC_SEQ_CST -D__UINT32_TYPE__ -D__UINTPTR_TYPE__ -D__DEC64_SUBNORMAL_MIN__ -D__DEC128_MANT_DIG__ -D__LDBL_MIN_10_EXP__ -D__SSE_MATH__ -D__SIZEOF_LONG_LONG__ -D__cpp_user_defined_literals -D__GCC_ATOMIC_LLONG_LOCK_FREE -D__LDBL_DIG__ -D__FLT_DECIMAL_DIG__ -D__UINT_FAST16_MAX__ -D__FLT_MIN_10_EXP__ -D__GCC_ATOMIC_SHORT_LOCK_FREE -D__UINT_FAST8_TYPE__ -D_GNU_SOURCE -D__ATOMIC_ACQ_REL -D__ATOMIC_RELEASE -O2 -fomit-frame-pointer -Wall -Wno-multichar -Wsign-compare -Wundef -Wwrite-strings -Wpointer-arith -W -Wno-unused-parameter -Wredundant-decls -Wformat=2 -Wformat-security -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-but-set-parameter -Winit-self -fno-strict-aliasing -Wcast-qual -fno-strict-overflow -Wnon-virtual-dtor -Wno-free-nonheap-object -rdynamic -DUNIX -D_FORTIFY_SOURCE=2 -DWITH_SSE -DWITH_ZLIB -DWITH_LZMA -DWITH_LZO -D_SQ64 -DWITH_PNG -DDEDICATED -DENABLE_NETWORK -DNDEBUG -DWITH_PERSONAL_DIR -DPERSONAL_DIR=".openttd" -DGLOBAL_DATA_DIR="/usr/local/share/games/openttd" -std=gnu++0x -Wno-narrowing +SORT = sort -u +AWK = awk +CONFIG_CACHE_COMPILER = $(SRC_OBJS_DIR)/config.cache.compiler +CONFIG_CACHE_LINKER = $(SRC_OBJS_DIR)/config.cache.linker +CONFIG_CACHE_ENDIAN = $(SRC_OBJS_DIR)/config.cache.endian +CONFIG_CACHE_SOURCE = $(SRC_OBJS_DIR)/config.cache.source +CONFIG_CACHE_VERSION = $(SRC_OBJS_DIR)/config.cache.version + +OBJS_C := +OBJS_CPP := 3rdparty/md5/md5.o 3rdparty/squirrel/sqstdlib/sqstdaux.o 3rdparty/squirrel/sqstdlib/sqstdmath.o 3rdparty/squirrel/squirrel/sqapi.o 3rdparty/squirrel/squirrel/sqbaselib.o 3rdparty/squirrel/squirrel/sqclass.o 3rdparty/squirrel/squirrel/sqcompiler.o 3rdparty/squirrel/squirrel/sqdebug.o 3rdparty/squirrel/squirrel/sqfuncstate.o 3rdparty/squirrel/squirrel/sqlexer.o 3rdparty/squirrel/squirrel/sqmem.o 3rdparty/squirrel/squirrel/sqobject.o 3rdparty/squirrel/squirrel/sqstate.o 3rdparty/squirrel/squirrel/sqtable.o 3rdparty/squirrel/squirrel/sqvm.o ai/ai_config.o ai/ai_core.o ai/ai_gui.o ai/ai_info.o ai/ai_instance.o ai/ai_scanner.o aircraft_cmd.o aircraft_gui.o airport.o airport_gui.o animated_tile.o articulated_vehicles.o autoreplace.o autoreplace_cmd.o autoreplace_gui.o base_consist.o blitter/base.o blitter/null.o bmp.o bootstrap_gui.o bridge_gui.o bridge_map.o build_vehicle_gui.o cargoaction.o cargomonitor.o cargopacket.o cargotype.o cheat.o cheat_gui.o clear_cmd.o command.o company_cmd.o company_gui.o console.o console_cmds.o console_gui.o core/alloc_func.o core/bitmath_func.o core/geometry_func.o core/math_func.o core/pool_func.o core/random_func.o cpu.o crashlog.o currency.o date.o date_gui.o debug.o dedicated.o departures.o departures_gui.o depot.o depot_cmd.o depot_gui.o disaster_vehicle.o dock_gui.o driver.o economy.o effectvehicle.o elrail.o engine.o engine_gui.o error_gui.o fileio.o fios.o fios_gui.o fontcache.o fontdetection.o game/game_config.o game/game_core.o game/game_info.o game/game_instance.o game/game_scanner.o game/game_text.o gamelog.o genworld.o genworld_gui.o gfx.o gfx_layout.o gfxinit.o goal.o goal_gui.o graph_gui.o ground_vehicle.o group_cmd.o group_gui.o heightmap.o highscore.o highscore_gui.o hotkeys.o industry_cmd.o industry_gui.o infrastructure.o ini.o ini_load.o intro_gui.o landscape.o linkgraph/demands.o linkgraph/flowmapper.o linkgraph/linkgraph.o linkgraph/linkgraph_gui.o linkgraph/linkgraphjob.o linkgraph/linkgraphschedule.o linkgraph/mcf.o linkgraph/refresh.o main_gui.o map.o misc.o misc/countedobj.o misc/dbg_helpers.o misc/getoptdata.o misc_cmd.o misc_gui.o mixer.o music.o music/null_m.o music_gui.o network/core/address.o network/core/core.o network/core/host.o network/core/packet.o network/core/tcp.o network/core/tcp_admin.o network/core/tcp_connect.o network/core/tcp_content.o network/core/tcp_game.o network/core/tcp_http.o network/core/udp.o network/network.o network/network_admin.o network/network_chat_gui.o network/network_client.o network/network_command.o network/network_content.o network/network_content_gui.o network/network_gamelist.o network/network_gui.o network/network_server.o network/network_udp.o newgrf.o newgrf_airport.o newgrf_airporttiles.o newgrf_canal.o newgrf_cargo.o newgrf_commons.o newgrf_config.o newgrf_debug_gui.o newgrf_engine.o newgrf_generic.o newgrf_gui.o newgrf_house.o newgrf_industries.o newgrf_industrytiles.o newgrf_object.o newgrf_railtype.o newgrf_sound.o newgrf_spritegroup.o newgrf_station.o newgrf_storage.o newgrf_text.o newgrf_town.o newgrf_townname.o news_gui.o object_cmd.o object_gui.o openttd.o order_backup.o order_cmd.o order_gui.o os/unix/crashlog_unix.o os/unix/unix.o osk_gui.o pathfinder/npf/aystar.o pathfinder/npf/npf.o pathfinder/npf/queue.o pathfinder/opf/opf_ship.o pathfinder/yapf/yapf_rail.o pathfinder/yapf/yapf_road.o pathfinder/yapf/yapf_ship.o pbs.o progress.o rail.o rail_cmd.o rail_gui.o rev.o road.o road_cmd.o road_gui.o road_map.o roadstop.o roadveh_cmd.o roadveh_gui.o saveload/afterload.o saveload/ai_sl.o saveload/airport_sl.o saveload/animated_tile_sl.o saveload/autoreplace_sl.o saveload/cargomonitor_sl.o saveload/cargopacket_sl.o saveload/cheat_sl.o saveload/company_sl.o saveload/depot_sl.o saveload/economy_sl.o saveload/engine_sl.o saveload/game_sl.o saveload/gamelog_sl.o saveload/goal_sl.o saveload/group_sl.o saveload/industry_sl.o saveload/labelmaps_sl.o saveload/linkgraph_sl.o saveload/map_sl.o saveload/misc_sl.o saveload/newgrf_sl.o saveload/object_sl.o saveload/oldloader.o saveload/oldloader_sl.o saveload/order_sl.o saveload/saveload.o saveload/signs_sl.o saveload/station_sl.o saveload/storage_sl.o saveload/story_sl.o saveload/strings_sl.o saveload/subsidy_sl.o saveload/town_sl.o saveload/vehicle_sl.o saveload/waypoint_sl.o screenshot.o script/api/script_accounting.o script/api/script_admin.o script/api/script_airport.o script/api/script_base.o script/api/script_basestation.o script/api/script_bridge.o script/api/script_bridgelist.o script/api/script_cargo.o script/api/script_cargolist.o script/api/script_cargomonitor.o script/api/script_company.o script/api/script_companymode.o script/api/script_controller.o script/api/script_date.o script/api/script_depotlist.o script/api/script_engine.o script/api/script_enginelist.o script/api/script_error.o script/api/script_event.o script/api/script_event_types.o script/api/script_execmode.o script/api/script_game.o script/api/script_gamesettings.o script/api/script_goal.o script/api/script_group.o script/api/script_grouplist.o script/api/script_industry.o script/api/script_industrylist.o script/api/script_industrytype.o script/api/script_industrytypelist.o script/api/script_infrastructure.o script/api/script_list.o script/api/script_log.o script/api/script_map.o script/api/script_marine.o script/api/script_news.o script/api/script_object.o script/api/script_order.o script/api/script_rail.o script/api/script_railtypelist.o script/api/script_road.o script/api/script_sign.o script/api/script_signlist.o script/api/script_station.o script/api/script_stationlist.o script/api/script_story_page.o script/api/script_storypageelementlist.o script/api/script_storypagelist.o script/api/script_subsidy.o script/api/script_subsidylist.o script/api/script_testmode.o script/api/script_text.o script/api/script_tile.o script/api/script_tilelist.o script/api/script_town.o script/api/script_townlist.o script/api/script_tunnel.o script/api/script_vehicle.o script/api/script_vehiclelist.o script/api/script_viewport.o script/api/script_waypoint.o script/api/script_waypointlist.o script/api/script_window.o script/script_config.o script/script_info.o script/script_info_dummy.o script/script_instance.o script/script_scanner.o script/squirrel.o script/squirrel_std.o settings.o settings_gui.o ship_cmd.o ship_gui.o signal.o signs.o signs_cmd.o signs_gui.o smallmap_gui.o sound.o sound/null_s.o sprite.o spritecache.o spriteloader/grf.o station.o station_cmd.o station_gui.o statusbar_gui.o story.o story_gui.o strgen/strgen_base.o string.o stringfilter.o strings.o subsidy.o subsidy_gui.o terraform_cmd.o terraform_gui.o textbuf.o texteff.o textfile_gui.o tgp.o thread/thread_pthread.o tile_map.o tilearea.o timetable_cmd.o timetable_gui.o toolbar_gui.o town_cmd.o town_gui.o townname.o train_cmd.o train_gui.o transparency_gui.o tree_cmd.o tree_gui.o tunnel_map.o tunnelbridge_cmd.o vehicle.o vehicle_cmd.o vehicle_gui.o vehiclelist.o video/dedicated_v.o video/null_v.o viewport.o viewport_gui.o viewport_sprite_sorter_sse4.o void_cmd.o watch_gui.o water_cmd.o waypoint.o waypoint_cmd.o waypoint_gui.o widget.o widgets/dropdown.o window.o +OBJS_MM := +OBJS_RC := +OBJS := $(OBJS_C) $(OBJS_CPP) $(OBJS_MM) $(OBJS_RC) +SRCS := 3rdparty/md5/md5.cpp 3rdparty/squirrel/sqstdlib/sqstdaux.cpp 3rdparty/squirrel/sqstdlib/sqstdmath.cpp 3rdparty/squirrel/squirrel/sqapi.cpp 3rdparty/squirrel/squirrel/sqbaselib.cpp 3rdparty/squirrel/squirrel/sqclass.cpp 3rdparty/squirrel/squirrel/sqcompiler.cpp 3rdparty/squirrel/squirrel/sqdebug.cpp 3rdparty/squirrel/squirrel/sqfuncstate.cpp 3rdparty/squirrel/squirrel/sqlexer.cpp 3rdparty/squirrel/squirrel/sqmem.cpp 3rdparty/squirrel/squirrel/sqobject.cpp 3rdparty/squirrel/squirrel/sqstate.cpp 3rdparty/squirrel/squirrel/sqtable.cpp 3rdparty/squirrel/squirrel/sqvm.cpp ai/ai_config.cpp ai/ai_core.cpp ai/ai_gui.cpp ai/ai_info.cpp ai/ai_instance.cpp ai/ai_scanner.cpp aircraft_cmd.cpp aircraft_gui.cpp airport.cpp airport_gui.cpp animated_tile.cpp articulated_vehicles.cpp autoreplace.cpp autoreplace_cmd.cpp autoreplace_gui.cpp base_consist.cpp blitter/base.cpp blitter/null.cpp bmp.cpp bootstrap_gui.cpp bridge_gui.cpp bridge_map.cpp build_vehicle_gui.cpp cargoaction.cpp cargomonitor.cpp cargopacket.cpp cargotype.cpp cheat.cpp cheat_gui.cpp clear_cmd.cpp command.cpp company_cmd.cpp company_gui.cpp console.cpp console_cmds.cpp console_gui.cpp core/alloc_func.cpp core/bitmath_func.cpp core/geometry_func.cpp core/math_func.cpp core/pool_func.cpp core/random_func.cpp cpu.cpp crashlog.cpp currency.cpp date.cpp date_gui.cpp debug.cpp dedicated.cpp departures.cpp departures_gui.cpp depot.cpp depot_cmd.cpp depot_gui.cpp disaster_vehicle.cpp dock_gui.cpp driver.cpp economy.cpp effectvehicle.cpp elrail.cpp engine.cpp engine_gui.cpp error_gui.cpp fileio.cpp fios.cpp fios_gui.cpp fontcache.cpp fontdetection.cpp game/game_config.cpp game/game_core.cpp game/game_info.cpp game/game_instance.cpp game/game_scanner.cpp game/game_text.cpp gamelog.cpp genworld.cpp genworld_gui.cpp gfx.cpp gfx_layout.cpp gfxinit.cpp goal.cpp goal_gui.cpp graph_gui.cpp ground_vehicle.cpp group_cmd.cpp group_gui.cpp heightmap.cpp highscore.cpp highscore_gui.cpp hotkeys.cpp industry_cmd.cpp industry_gui.cpp infrastructure.cpp ini.cpp ini_load.cpp intro_gui.cpp landscape.cpp linkgraph/demands.cpp linkgraph/flowmapper.cpp linkgraph/linkgraph.cpp linkgraph/linkgraph_gui.cpp linkgraph/linkgraphjob.cpp linkgraph/linkgraphschedule.cpp linkgraph/mcf.cpp linkgraph/refresh.cpp main_gui.cpp map.cpp misc.cpp misc/countedobj.cpp misc/dbg_helpers.cpp misc/getoptdata.cpp misc_cmd.cpp misc_gui.cpp mixer.cpp music.cpp music/null_m.cpp music_gui.cpp network/core/address.cpp network/core/core.cpp network/core/host.cpp network/core/packet.cpp network/core/tcp.cpp network/core/tcp_admin.cpp network/core/tcp_connect.cpp network/core/tcp_content.cpp network/core/tcp_game.cpp network/core/tcp_http.cpp network/core/udp.cpp network/network.cpp network/network_admin.cpp network/network_chat_gui.cpp network/network_client.cpp network/network_command.cpp network/network_content.cpp network/network_content_gui.cpp network/network_gamelist.cpp network/network_gui.cpp network/network_server.cpp network/network_udp.cpp newgrf.cpp newgrf_airport.cpp newgrf_airporttiles.cpp newgrf_canal.cpp newgrf_cargo.cpp newgrf_commons.cpp newgrf_config.cpp newgrf_debug_gui.cpp newgrf_engine.cpp newgrf_generic.cpp newgrf_gui.cpp newgrf_house.cpp newgrf_industries.cpp newgrf_industrytiles.cpp newgrf_object.cpp newgrf_railtype.cpp newgrf_sound.cpp newgrf_spritegroup.cpp newgrf_station.cpp newgrf_storage.cpp newgrf_text.cpp newgrf_town.cpp newgrf_townname.cpp news_gui.cpp object_cmd.cpp object_gui.cpp openttd.cpp order_backup.cpp order_cmd.cpp order_gui.cpp os/unix/crashlog_unix.cpp os/unix/unix.cpp osk_gui.cpp pathfinder/npf/aystar.cpp pathfinder/npf/npf.cpp pathfinder/npf/queue.cpp pathfinder/opf/opf_ship.cpp pathfinder/yapf/yapf_rail.cpp pathfinder/yapf/yapf_road.cpp pathfinder/yapf/yapf_ship.cpp pbs.cpp progress.cpp rail.cpp rail_cmd.cpp rail_gui.cpp rev.cpp road.cpp road_cmd.cpp road_gui.cpp road_map.cpp roadstop.cpp roadveh_cmd.cpp roadveh_gui.cpp saveload/afterload.cpp saveload/ai_sl.cpp saveload/airport_sl.cpp saveload/animated_tile_sl.cpp saveload/autoreplace_sl.cpp saveload/cargomonitor_sl.cpp saveload/cargopacket_sl.cpp saveload/cheat_sl.cpp saveload/company_sl.cpp saveload/depot_sl.cpp saveload/economy_sl.cpp saveload/engine_sl.cpp saveload/game_sl.cpp saveload/gamelog_sl.cpp saveload/goal_sl.cpp saveload/group_sl.cpp saveload/industry_sl.cpp saveload/labelmaps_sl.cpp saveload/linkgraph_sl.cpp saveload/map_sl.cpp saveload/misc_sl.cpp saveload/newgrf_sl.cpp saveload/object_sl.cpp saveload/oldloader.cpp saveload/oldloader_sl.cpp saveload/order_sl.cpp saveload/saveload.cpp saveload/signs_sl.cpp saveload/station_sl.cpp saveload/storage_sl.cpp saveload/story_sl.cpp saveload/strings_sl.cpp saveload/subsidy_sl.cpp saveload/town_sl.cpp saveload/vehicle_sl.cpp saveload/waypoint_sl.cpp screenshot.cpp script/api/script_accounting.cpp script/api/script_admin.cpp script/api/script_airport.cpp script/api/script_base.cpp script/api/script_basestation.cpp script/api/script_bridge.cpp script/api/script_bridgelist.cpp script/api/script_cargo.cpp script/api/script_cargolist.cpp script/api/script_cargomonitor.cpp script/api/script_company.cpp script/api/script_companymode.cpp script/api/script_controller.cpp script/api/script_date.cpp script/api/script_depotlist.cpp script/api/script_engine.cpp script/api/script_enginelist.cpp script/api/script_error.cpp script/api/script_event.cpp script/api/script_event_types.cpp script/api/script_execmode.cpp script/api/script_game.cpp script/api/script_gamesettings.cpp script/api/script_goal.cpp script/api/script_group.cpp script/api/script_grouplist.cpp script/api/script_industry.cpp script/api/script_industrylist.cpp script/api/script_industrytype.cpp script/api/script_industrytypelist.cpp script/api/script_infrastructure.cpp script/api/script_list.cpp script/api/script_log.cpp script/api/script_map.cpp script/api/script_marine.cpp script/api/script_news.cpp script/api/script_object.cpp script/api/script_order.cpp script/api/script_rail.cpp script/api/script_railtypelist.cpp script/api/script_road.cpp script/api/script_sign.cpp script/api/script_signlist.cpp script/api/script_station.cpp script/api/script_stationlist.cpp script/api/script_story_page.cpp script/api/script_storypageelementlist.cpp script/api/script_storypagelist.cpp script/api/script_subsidy.cpp script/api/script_subsidylist.cpp script/api/script_testmode.cpp script/api/script_text.cpp script/api/script_tile.cpp script/api/script_tilelist.cpp script/api/script_town.cpp script/api/script_townlist.cpp script/api/script_tunnel.cpp script/api/script_vehicle.cpp script/api/script_vehiclelist.cpp script/api/script_viewport.cpp script/api/script_waypoint.cpp script/api/script_waypointlist.cpp script/api/script_window.cpp script/script_config.cpp script/script_info.cpp script/script_info_dummy.cpp script/script_instance.cpp script/script_scanner.cpp script/squirrel.cpp script/squirrel_std.cpp settings.cpp settings_gui.cpp ship_cmd.cpp ship_gui.cpp signal.cpp signs.cpp signs_cmd.cpp signs_gui.cpp smallmap_gui.cpp sound.cpp sound/null_s.cpp sprite.cpp spritecache.cpp spriteloader/grf.cpp station.cpp station_cmd.cpp station_gui.cpp statusbar_gui.cpp story.cpp story_gui.cpp strgen/strgen_base.cpp string.cpp stringfilter.cpp strings.cpp subsidy.cpp subsidy_gui.cpp terraform_cmd.cpp terraform_gui.cpp textbuf.cpp texteff.cpp textfile_gui.cpp tgp.cpp thread/thread_pthread.cpp tile_map.cpp tilearea.cpp timetable_cmd.cpp timetable_gui.cpp toolbar_gui.cpp town_cmd.cpp town_gui.cpp townname.cpp train_cmd.cpp train_gui.cpp transparency_gui.cpp tree_cmd.cpp tree_gui.cpp tunnel_map.cpp tunnelbridge_cmd.cpp vehicle.cpp vehicle_cmd.cpp vehicle_gui.cpp vehiclelist.cpp video/dedicated_v.cpp video/null_v.cpp viewport.cpp viewport_gui.cpp viewport_sprite_sorter_sse4.cpp void_cmd.cpp watch_gui.cpp water_cmd.cpp waypoint.cpp waypoint_cmd.cpp waypoint_gui.cpp widget.cpp widgets/dropdown.cpp window.cpp + +# All C-files depend on those 3 files +FILE_DEP := $(CONFIG_CACHE_COMPILER) endian_target.h +# Create all dirs and subdirs +RES := $(shell mkdir -p $(BIN_DIR) $(sort $(dir $(OBJS)))) + +# Make sure endian_target.h is reasable as if it was in the src/ dir +CFLAGS += -I $(SRC_OBJS_DIR) -I $(LANG_OBJS_DIR) -I $(SETTING_OBJS_DIR) +CFLAGS_MAKEDEP += -I $(SRC_OBJS_DIR) -I $(LANG_OBJS_DIR) -I $(SETTING_OBJS_DIR) +ifdef SCRIPT_SRC_DIR + CFLAGS_MAKEDEP += -I $(SCRIPT_SRC_DIR) +endif + +ENDIAN_TARGETS := endian_target.h $(ENDIAN_CHECK) + +# Check if we want to show what we are doing +ifdef VERBOSE + Q = + E = @true +else + Q = @ + E = @echo +endif + +# Our default target +all: $(BIN_DIR)/$(TTD) + +# This are 2 rules that are pointing back to STRGEN stuff. +# There is not really a need to have them here, but in case +# some weirdo wants to run 'make' in the 'src' dir and expects +# the languages to be recompiled, this catches that case and +# takes care of it nicely. +$(LANG_OBJS_DIR)/$(STRGEN): + $(MAKE) -C $(LANG_OBJS_DIR) $(STRGEN) + +$(LANG_OBJS_DIR)/table/strings.h: $(LANG_DIR)/english.txt $(LANG_OBJS_DIR)/$(STRGEN) + $(MAKE) -C $(LANG_OBJS_DIR) table/strings.h + +# Always run version detection, so we always have an accurate modified +# flag +VERSIONS := $(shell AWK="$(AWK)" "$(ROOT_DIR)/findversion.sh") +MODIFIED := $(shell echo "$(VERSIONS)" | cut -f 3 -d' ') + +# Use autodetected revisions +REV := $(shell echo "$(VERSIONS)" | cut -f 1 -d' ') +REV_NR := $(shell echo "$(VERSIONS)" | cut -f 2 -d' ') + +# Make sure we have something in REV and REV_NR +ifeq ($(REV),) +REV := norev000 +endif +ifeq ($(REV_NR),) +REV_NR := 0 +endif + +# This helps to recompile if flags change +RES := $(shell if [ "`cat $(CONFIG_CACHE_COMPILER) 2>/dev/null`" != "$(CFLAGS) $(CXXFLAGS)" ]; then echo "$(CFLAGS) $(CXXFLAGS)" > $(CONFIG_CACHE_COMPILER); fi ) +RES := $(shell if [ "`cat $(CONFIG_CACHE_LINKER) 2>/dev/null`" != "$(LDFLAGS) $(LIBS)" ]; then echo "$(LDFLAGS) $(LIBS)" > $(CONFIG_CACHE_LINKER); fi ) +RES := $(shell if [ "`cat $(CONFIG_CACHE_ENDIAN) 2>/dev/null`" != "$(ENDIAN_FORCE)" ]; then echo "$(ENDIAN_FORCE)" > $(CONFIG_CACHE_ENDIAN); fi ) + +# If there is a change in the source-file-list, make sure we recheck the deps +RES := $(shell if [ "`cat $(CONFIG_CACHE_SOURCE) 2>/dev/null`" != "$(SRCS)" ]; then echo "$(SRCS)" > $(CONFIG_CACHE_SOURCE); fi ) +# If there is a change in the revision, make sure we recompile rev.cpp +RES := $(shell if [ "`cat $(CONFIG_CACHE_VERSION) 2>/dev/null`" != "$(REV) $(MODIFIED)" ]; then echo "$(REV) $(MODIFIED)" > $(CONFIG_CACHE_VERSION); fi ) + +ifndef MAKEDEPEND +# The slow, but always correct, dep-check +DEP_MASK := %.d +DEPS := $(OBJS:%.o=%.d) + +# Only include the deps if we are compiling everything +ifeq ($(filter $(ENDIAN_TARGETS) %.o clean mrproper, $(MAKECMDGOALS)),) +-include $(DEPS) +else +# In case we want to compile a single target, include the .d file for it +ifneq ($(filter %.o, $(MAKECMDGOALS)),) +SINGLE_DEP := $(filter %.o, $(MAKECMDGOALS)) +-include $(SINGLE_DEP:%.o=%.d) +endif +endif + +# Find the deps via GCC. Rarely wrong, but a bit slow + +$(OBJS_C:%.o=%.d): %.d: $(SRC_DIR)/%.c $(FILE_DEP) + $(E) '$(STAGE) DEP $(<:$(SRC_DIR)/%.c=%.c)' + $(Q)$(CC_HOST) $(CFLAGS) -MM $< | sed 's@^$(@F:%.d=%.o):@$@ $(@:%.d=%.o):@' > $@ + +$(OBJS_CPP:%.o=%.d): %.d: $(SRC_DIR)/%.cpp $(FILE_DEP) + $(E) '$(STAGE) DEP $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_HOST) $(CFLAGS) $(CXXFLAGS) -MM $< | sed 's@^$(@F:%.d=%.o):@$@ $(@:%.d=%.o):@' > $@ + +$(OBJS_MM:%.o=%.d): %.d: $(SRC_DIR)/%.mm $(FILE_DEP) + $(E) '$(STAGE) DEP $(<:$(SRC_DIR)/%.mm=%.mm)' + $(Q)$(CC_HOST) $(CFLAGS) -MM $< | sed 's@^$(@F:%.d=%.o):@$@ $(@:%.d=%.o):@' > $@ + +$(OBJS_RC:%.o=%.d): %.d: $(SRC_DIR)/%.rc $(FILE_DEP) + $(E) '$(STAGE) DEP $(<:$(SRC_DIR)/%.rc=%.rc)' + $(Q)touch $@ + +else +# The much faster, but can be wrong, dep-check +DEP_MASK := +DEPS := Makefile.dep + +# Only include the deps if we are not cleaning +ifeq ($(filter $(ENDIAN_TARGETS) depend clean mrproper, $(MAKECMDGOALS)),) +-include Makefile.dep +endif + +ifeq ("$(SRC_OBJS_DIR)/$(DEPEND)","$(MAKEDEPEND)") +DEP := $(MAKEDEPEND) +$(SRC_OBJS_DIR)/$(DEPEND): $(SRC_DIR)/depend/depend.cpp + $(E) '$(STAGE) Compiling and linking $(DEPEND)' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) $(LDFLAGS_BUILD) -o $@ $< +endif + +# Make sure that only 'make depend' ALWAYS triggers a recheck +ifeq ($(filter depend, $(MAKECMDGOALS)),) +Makefile.dep: $(FILE_DEP) $(SRCS:%=$(SRC_DIR)/%) $(CONFIG_CACHE_SOURCE) $(DEP) +else +Makefile.dep: $(FILE_DEP) $(SRCS:%=$(SRC_DIR)/%) $(DEP) FORCE +endif + $(E) '$(STAGE) DEP CHECK (all files)' + $(Q)rm -f Makefile.dep.tmp + $(Q)touch Makefile.dep.tmp + +# Calculate the deps via makedepend + $(Q)$(MAKEDEPEND) -f$(SRC_OBJS_DIR)/Makefile.dep.tmp -o.o -Y -v -- $(CFLAGS_MAKEDEP) -- $(SRCS:%=$(SRC_DIR)/%) 2>/dev/null + +# Convert x:/... paths to /x/... for mingw +ifeq ($(OS), MINGW) + @cat Makefile.dep.tmp | sed 's@/\([a-zA-Z]\):\/@\/\1\/@g' > Makefile.dep.tmp.mingw + @cp Makefile.dep.tmp.mingw Makefile.dep.tmp + @rm -f Makefile.dep.tmp.mingw +endif + +# Remove all comments and includes that don't start with $(SRC_DIR) +# Remove $(SRC_DIR) from object-file-name + @$(AWK) ' \ + /^# DO NOT/ { print $$0 ; next} \ + /^#/ {next} \ + /: / { \ + left = NF - 1; \ + for (n = 2; n <= NF; n++) { \ + if (match($$n, "^$(ROOT_DIR)") == 0) { \ + $$n = ""; \ + left--; \ + } \ + } \ + gsub("$(SRC_DIR)/", "", $$1); \ + if (left > 0) { \ + print $$0; \ + $$1 = "Makefile.dep:"; \ + print $$0; \ + } \ + next \ + } \ + { \ + print $$0 \ + } \ + ' < Makefile.dep.tmp | sed 's@ *@ @g;s@ $$@@' | $(SORT) > Makefile.dep + + $(Q)rm -f Makefile.dep.tmp Makefile.dep.tmp.bak + +endif + +# Avoid problems with deps if a .h/.hpp/.hpp.sq file is deleted without the deps +# being updated. Now the Makefile continues, the deps are recreated +# and all will be fine. +%.h %.hpp %.hpp.sq: + @true + + +# Compile all the files according to the targets + +$(OBJS_C): %.o: $(SRC_DIR)/%.c $(DEP_MASK) $(FILE_DEP) + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.c=%.c)' + $(Q)$(CC_HOST) $(CFLAGS) -c -o $@ $< + +$(filter-out %sse2.o, $(filter-out %ssse3.o, $(filter-out %sse4.o, $(OBJS_CPP)))): %.o: $(SRC_DIR)/%.cpp $(DEP_MASK) $(FILE_DEP) + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_HOST) $(CFLAGS) $(CXXFLAGS) -c -o $@ $< + +$(filter %sse2.o, $(OBJS_CPP)): %.o: $(SRC_DIR)/%.cpp $(DEP_MASK) $(FILE_DEP) + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_HOST) $(CFLAGS) $(CXXFLAGS) -c -msse2 -o $@ $< + +$(filter %ssse3.o, $(OBJS_CPP)): %.o: $(SRC_DIR)/%.cpp $(DEP_MASK) $(FILE_DEP) + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_HOST) $(CFLAGS) $(CXXFLAGS) -c -mssse3 -o $@ $< + +$(filter %sse4.o, $(OBJS_CPP)): %.o: $(SRC_DIR)/%.cpp $(DEP_MASK) $(FILE_DEP) + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_HOST) $(CFLAGS) $(CXXFLAGS) -c -msse4.1 -o $@ $< + +$(OBJS_MM): %.o: $(SRC_DIR)/%.mm $(DEP_MASK) $(FILE_DEP) + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.mm=%.mm)' + $(Q)$(CC_HOST) $(CFLAGS) -c -o $@ $< + +$(OBJS_RC): %.o: $(SRC_DIR)/%.rc $(FILE_DEP) + $(E) '$(STAGE) Compiling resource $(<:$(SRC_DIR)/%.rc=%.rc)' + $(Q)$(WINDRES) -o $@ -I `basename $<` $< + +$(BIN_DIR)/$(TTD): $(TTD) + $(Q)cp $(TTD) $(BIN_DIR)/$(TTD) +ifeq ($(OS), UNIX) + $(Q)cp $(MEDIA_DIR)/openttd.32.bmp $(BIN_DIR)/baseset/ +endif +ifeq ($(OS), OSX) + $(Q)cp $(ROOT_DIR)/os/macosx/splash.png $(BIN_DIR)/baseset/ +endif + +$(TTD): $(OBJS) $(CONFIG_CACHE_LINKER) + $(E) '$(STAGE) Linking $@' +ifeq ($(OS), PSP) + # Because of a bug in the PSP GCC tools, linking via CXX results + # in total chaos and more problems then you can handle. So we need + # CC to link OpenTTD for PSP + $(Q)+$(CC_HOST) $(LDFLAGS) $(OBJS) $(LIBS) -o $@ +else + $(Q)+$(CXX_HOST) $(LDFLAGS) $(OBJS) $(LIBS) -o $@ +endif +ifdef STRIP + $(Q)$(STRIP) $@ +endif +ifeq ($(OS), DOS) + $(E) '$(STAGE) Adding CWSDPMI stub to $@' + $(Q)$(ROOT_DIR)/os/dos/make_dos_binary_selfcontained.sh $(SRC_OBJS_DIR)/$@ +endif + +# The targets to compile the endian-code + +endian_target.h: $(ENDIAN_CHECK) $(CONFIG_CACHE_ENDIAN) + $(E) '$(STAGE) Testing endianness for target' + $(Q)./$(ENDIAN_CHECK) $(ENDIAN_FORCE) > $@ + +$(ENDIAN_CHECK): $(SRC_DIR)/endian_check.cpp + $(E) '$(STAGE) Compiling and Linking $@' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) $(LDFLAGS_BUILD) $< -o $@ + +# Revision files + +$(SRC_DIR)/rev.cpp: $(CONFIG_CACHE_VERSION) $(SRC_DIR)/rev.cpp.in + $(Q)cat $(SRC_DIR)/rev.cpp.in | sed "s@\!\!REVISION\!\!@$(REV_NR)@g;s@!!VERSION!!@$(REV)@g;s@!!MODIFIED!!@$(MODIFIED)@g;s@!!DATE!!@`date +%d.%m.%y`@g" > $(SRC_DIR)/rev.cpp + +$(SRC_DIR)/os/windows/ottdres.rc: $(CONFIG_CACHE_VERSION) $(SRC_DIR)/os/windows/ottdres.rc.in + $(Q)cat $(SRC_DIR)/os/windows/ottdres.rc.in | sed "s@\!\!REVISION\!\!@$(REV_NR)@g;s@!!VERSION!!@$(REV)@g;s@!!DATE!!@`date +%d.%m.%y`@g" > $(SRC_DIR)/os/windows/ottdres.rc + +FORCE: + +depend: $(DEPS) + +clean: + $(E) '$(STAGE) Cleaning up object files' + $(Q)rm -f $(DEPS) $(OBJS) $(TTD) $(DEPEND) $(TTD:%=$(BIN_DIR)/%) $(BIN_DIR)/baseset/openttd.32.bmp $(CONFIG_CACHE_COMPILER) $(CONFIG_CACHE_LINKER) $(CONFIG_CACHE_ENDIAN) $(CONFIG_CACHE_SOURCE) $(ENDIAN_TARGETS) + +mrproper: clean + $(Q)rm -f $(SRC_DIR)/rev.cpp $(SRC_DIR)/os/windows/ottdres.rc + +%.o: + @echo '$(STAGE) No such source-file: $(@:%.o=%).[c|cpp|mm|rc]' + +.PHONY: all mrproper depend clean FORCE diff --git a/objs/release/config.cache.version b/objs/release/config.cache.version new file mode 100644 index 0000000..e5e7db8 --- /dev/null +++ b/objs/release/config.cache.version @@ -0,0 +1 @@ +norev000 1 diff --git a/objs/setting/Makefile b/objs/setting/Makefile new file mode 100644 index 0000000..b086fa2 --- /dev/null +++ b/objs/setting/Makefile @@ -0,0 +1,79 @@ +# Auto-generated file from 'Makefile.settings.in' -- DO NOT EDIT +# $Id$ + +# This file is part of OpenTTD. +# OpenTTD 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, version 2. +# OpenTTD 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 OpenTTD. If not, see . + +SETTINGSGEN = settings_gen +ENDIAN_CHECK = endian_check +SRC_DIR = /home/openttd/openttd-virj-source/src +CXX_BUILD = g++ +CFLAGS_BUILD = -Wall -Wno-multichar -Wsign-compare -Wundef -Wwrite-strings -Wpointer-arith -W -Wno-unused-parameter -Wredundant-decls -Wformat=2 -Wformat-security -Wno-unused-variable -Wno-unused-but-set-variable -Wno-unused-but-set-parameter -Winit-self -fno-strict-aliasing -Wcast-qual -fno-strict-overflow -Wnon-virtual-dtor -Wno-free-nonheap-object -rdynamic -DUNIX -D_FORTIFY_SOURCE=2 -O1 -DNDEBUG +CXXFLAGS_BUILD = -std=gnu++0x -Wno-narrowing +LDFLAGS_BUILD = -rdynamic +STAGE = [SETTING] +SETTING_OBJS_DIR = /home/openttd/openttd-virj-source/objs/setting + +ENDIAN_TARGETS := endian_host.h endian_target.h $(ENDIAN_CHECK) + +# Check if we want to show what we are doing +ifdef VERBOSE + Q = + E = @true +else + Q = @ + E = @echo +endif + +all: table/settings.h + +settingsgen.o: $(SRC_DIR)/settingsgen/settingsgen.cpp $(SRC_DIR)/string_func.h $(SRC_DIR)/strings_type.h $(SRC_DIR)/misc/getoptdata.h $(SRC_DIR)/ini_type.h $(SRC_DIR)/core/smallvec_type.hpp $(SRC_DIR)/safeguards.h + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSETTINGSGEN -c -o $@ $< + +alloc_func.o: $(SRC_DIR)/core/alloc_func.cpp endian_host.h $(SRC_DIR)/safeguards.h + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSETTINGSGEN -c -o $@ $< + +getoptdata.o: $(SRC_DIR)/misc/getoptdata.cpp $(SRC_DIR)/misc/getoptdata.h $(SRC_DIR)/safeguards.h + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/misc/%.cpp=%.cpp)' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSETTINGSGEN -c -o $@ $< + +string.o: $(SRC_DIR)/string.cpp endian_host.h $(SRC_DIR)/safeguards.h + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSETTINGSGEN -c -o $@ $< + +ini_load.o: $(SRC_DIR)/ini_load.cpp $(SRC_DIR)/core/alloc_func.hpp $(SRC_DIR)/core/mem_func.hpp $(SRC_DIR)/ini_type.h $(SRC_DIR)/string_func.h $(SRC_DIR)/safeguards.h + $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSETTINGSGEN -c -o $@ $< + +$(SETTINGSGEN): alloc_func.o string.o ini_load.o settingsgen.o getoptdata.o + $(E) '$(STAGE) Compiling and Linking $@' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) $(LDFLAGS_BUILD) $^ -o $@ + +table/settings.h: $(SETTINGSGEN) $(SRC_DIR)/table/settings.h.preamble $(SRC_DIR)/table/settings.h.postamble $(SRC_DIR)/table/*.ini + $(E) '$(STAGE) Generating $@' + @mkdir -p table + $(Q)./$(SETTINGSGEN) -o table/settings.h -b $(SRC_DIR)/table/settings.h.preamble -a $(SRC_DIR)/table/settings.h.postamble $(SRC_DIR)/table/*.ini + +# The targets to compile the endian-code + +endian_host.h: $(ENDIAN_CHECK) + $(E) '$(STAGE) Testing endianness for host' + $(Q)./$(ENDIAN_CHECK) > $@ + +$(ENDIAN_CHECK): $(SRC_DIR)/endian_check.cpp + $(E) '$(STAGE) Compiling and Linking $@' + $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) $(LDFLAGS_BUILD) $< -o $@ + +depend: + +clean: + $(E) '$(STAGE) Cleaning up settings files' + $(Q)rm -f settingsgen.o alloc_func.o getoptdata.o ini_load.o $(SETTINGSGEN) $(ENDIAN_TARGETS) table/settings.h + +mrproper: clean + +.PHONY: all mrproper depend clean diff --git a/objs/setting/string.o b/objs/setting/string.o new file mode 100644 index 0000000..ad1bc56 Binary files /dev/null and b/objs/setting/string.o differ diff --git a/os/debian/NEWS b/os/debian/NEWS new file mode 100644 index 0000000..2a5c811 --- /dev/null +++ b/os/debian/NEWS @@ -0,0 +1,25 @@ +openttd (1.0.0~rc3-2) unstable; urgency=low + + The openttd package has been moved from contrib into main. Since the + OpenGFX free graphics set has been packaged for Debian, one can now run + OpenTTD without needing any of the resources from the original game + (though the original resources are still supported). + + -- Matthijs Kooijman Thu, 18 Mar 2010 13:09:35 +0100 + +openttd (0.7.0-1) unstable; urgency=low + + Handling of AI players has changed in 0.7.0. This package no longer + contains any AI players, so playing against the computer is not possible + out of the box any longer. However, you can easily download AI players + through the new "Content Downloading Service", after which playing with + computer players is possible. + + Loading old savegames with computer players is supported (AI players will + be converted according to the current AI settings), but at this moment + there are no AIs that completely handle any existing infrastructure built + by the old AI, so starting a new game might be more fun (especially since + most of the new AIs are a lot less erratic). + + -- Matthijs Kooijman Mon, 13 Apr 2009 15:11:20 +0200 + diff --git a/os/debian/README.Debian b/os/debian/README.Debian new file mode 100644 index 0000000..e7b4bdb --- /dev/null +++ b/os/debian/README.Debian @@ -0,0 +1,41 @@ +OpenTTD for Debian +------------------ + +To properly play this game, you need a base graphics and sound set. +Currently, the graphics, sound and music files from the original +Transport Tycoon Deluxe game (Windows and DOS versions) are supported, +as well as the free graphics replacement set "OpenGFX", sound +replacement set "OpenSFX" (which is in non-free due to a restrictive +license) and the free music replacement set "OpenMSX". + +Normally, installing the openttd package should automatically install +openttd-opengfx as well, allowing OpenTTD to run out of the box. If you +want sound, you'll have to enable non-free sources and install the +openttd-opensfx package manually (or install the original Transport +Tyccon Deluxe sound files). + +The easiest way to install the OpenMSX music files is to use the in-game +content download system, which should offer the latest version of the +music files. + +To find out how to install the original Transport Tycoon Deluxe graphics +sound files and music files, see readme.txt, section 4.1. + +-Playing Music + In addition to installing a music set (see above), you'll also need + to install the timidity midi player, available in the timidity + package. + + Remember that not all audio devices support multiple audiostreams + (music and sound), so you might have to use alsa software mixing or + pulseaudio. + +-Scenarios + There are no scenarios included in this release. Scenarios can be + downloaded using OpenTTD's content service, which is available from + OpenTTD's main menu. If you have obtained a scenario through other + means, you can place it either in your ~/.openttd/scenario directory + or in the system-wide /usr/share/games/openttd/scenario directory. + + -- Matthijs Kooijman Mon, 01 Feb 2010 10:42:11 +0100 + diff --git a/os/debian/changelog b/os/debian/changelog new file mode 100644 index 0000000..4dd5b11 --- /dev/null +++ b/os/debian/changelog @@ -0,0 +1,945 @@ +openttd (1.5.3-0) unstable; urgency=low + + * New upstream release 1.5.3 + + -- OpenTTD Tue, 01 Dec 2015 21:00:00 +0100 + +openttd (1.5.3~RC1-0) unstable; urgency=low + + * New upstream release 1.5.3-RC1 + + -- OpenTTD Sun, 01 Nov 2015 14:00:00 +0100 + +openttd (1.5.2-0) unstable; urgency=low + + * New upstream release 1.5.2 + + -- OpenTTD Tue, 01 Sep 2015 21:00:00 +0200 + +openttd (1.5.2~RC1-0) unstable; urgency=low + + * New upstream release 1.5.2-RC1 + + -- OpenTTD Sat, 01 Aug 2015 13:00:00 +0200 + +openttd (1.5.1-0) unstable; urgency=low + + * New upstream release 1.5.1 + + -- OpenTTD Mon, 01 Jun 2015 21:00:00 +0200 + +openttd (1.5.1~RC1-0) unstable; urgency=low + + * New upstream release 1.5.1-RC1 + + -- OpenTTD Fri, 08 May 2015 21:00:00 +0200 + +openttd (1.5.0-0) unstable; urgency=low + + * New upstream release 1.5.0 + + -- OpenTTD Wed, 01 Apr 2015 21:00:00 +0200 + +openttd (1.5.0~RC1-0) unstable; urgency=low + + * New upstream release 1.5.0-RC1 + + -- OpenTTD Wed, 18 Mar 2015 21:00:00 +0100 + +openttd (1.5.0~beta2-0) unstable; urgency=low + + * New upstream release 1.5.0-beta2 + + -- OpenTTD Tue, 24 Feb 2015 21:00:00 +0100 + +openttd (1.5.0~beta1-0) unstable; urgency=low + + * New upstream release 1.5.0-beta1 + + -- OpenTTD Wed, 24 Dec 2014 21:00:00 +0100 + +openttd (1.4.4-0) unstable; urgency=low + + * New upstream release 1.4.4 + + -- OpenTTD Tue, 21 Oct 2014 21:00:00 +0200 + +openttd (1.4.4~RC1-0) unstable; urgency=low + + * New upstream release 1.4.4-RC1 + + -- OpenTTD Wed, 08 Oct 2014 19:00:00 +0200 + +openttd (1.4.3-0) unstable; urgency=low + + * New upstream release 1.4.3 + + -- OpenTTD Tue, 23 Sep 2014 21:00:00 +0200 + +openttd (1.4.3~RC2-0) unstable; urgency=low + + * New upstream release 1.4.3-RC2 + + -- OpenTTD Sun, 14 Sep 2014 19:00:00 +0200 + +openttd (1.4.3~RC1-0) unstable; urgency=low + + * New upstream release 1.4.3-RC1 + + -- OpenTTD Sun, 07 Sep 2014 19:00:00 +0200 + +openttd (1.4.2-0) unstable; urgency=low + + * New upstream release 1.4.2 + + -- OpenTTD Sat, 16 Aug 2014 21:00:00 +0200 + +openttd (1.4.2~RC2-0) unstable; urgency=low + + * New upstream release 1.4.2-RC2 + + -- OpenTTD Sun, 03 Aug 2014 18:00:00 +0200 + +openttd (1.4.2~RC1-0) unstable; urgency=low + + * New upstream release 1.4.2-RC1 + + -- OpenTTD Thu, 03 Jul 2014 21:00:00 +0200 + +openttd (1.4.1-0) unstable; urgency=low + + * New upstream release 1.4.1 + + -- OpenTTD Mon, 02 Jun 2014 21:00:00 +0200 + +openttd (1.4.1~RC2-0) unstable; urgency=low + + * New upstream release 1.4.1-RC2 + + -- OpenTTD Sun, 18 May 2014 21:00:00 +0200 + +openttd (1.4.1~RC1-0) unstable; urgency=low + + * New upstream release 1.4.1-RC1 + + -- OpenTTD Sun, 04 May 2014 21:00:00 +0200 + +openttd (1.4.0-0) unstable; urgency=low + + * New upstream release 1.4.0 + + -- OpenTTD Tue, 01 Apr 2014 21:00:00 +0200 + +openttd (1.4.0~RC1-0) unstable; urgency=low + + * New upstream release 1.4.0-RC1 + + -- OpenTTD Tue, 17 Mar 2014 21:00:00 +0100 + +openttd (1.4.0~beta5-0) unstable; urgency=low + + * New upstream release 1.4.0-beta5 + + -- OpenTTD Tue, 25 Feb 2014 10:15:00 +0100 + +openttd (1.4.0~beta4-0) unstable; urgency=low + + * New upstream release 1.4.0-beta4 + + -- OpenTTD Thu, 06 Feb 2014 21:00:00 +0100 + +openttd (1.4.0~beta3-0) unstable; urgency=low + + * New upstream release 1.4.0-beta3 + + -- OpenTTD Tue, 21 Jan 2014 21:00:00 +0100 + +openttd (1.4.0~beta2-0) unstable; urgency=low + + * New upstream release 1.4.0-beta2 + + -- OpenTTD Tue, 07 Jan 2014 21:00:00 +0100 + +openttd (1.4.0~beta1-0) unstable; urgency=low + + * New upstream release 1.4.0-beta1 + + -- OpenTTD Tue, 24 Dec 2013 00:00:00 +0100 + +openttd (1.3.3-0) unstable; urgency=low + + * New upstream release 1.3.3 + + -- OpenTTD Fri, 29 Nov 2013 19:00:00 +0100 + +openttd (1.3.3~RC2-0) unstable; urgency=low + + * New upstream release 1.3.3-RC2 + + -- OpenTTD Sun, 24 Nov 2013 19:00:00 +0100 + +openttd (1.3.3~RC1-0) unstable; urgency=low + + * New upstream release 1.3.3-RC1 + + -- OpenTTD Sun, 17 Nov 2013 19:00:00 +0100 + +openttd (1.3.2-0) unstable; urgency=low + + * New upstream release 1.3.2 + + -- OpenTTD Sat, 27 Jul 2013 18:00:00 +0200 + +openttd (1.3.2~RC2-0) unstable; urgency=low + + * New upstream release 1.3.2-RC2 + + -- OpenTTD Sat, 13 Jul 2013 12:00:00 +0200 + +openttd (1.3.2~RC1-0) unstable; urgency=low + + * New upstream release 1.3.2-RC1 + + -- OpenTTD Sun, 30 Jun 2013 12:00:00 +0200 + +openttd (1.3.1-0) unstable; urgency=low + + * New upstream release 1.3.1 + + -- OpenTTD Sat, 01 Jun 2013 00:00:00 +0300 + +openttd (1.3.1~RC1-0) unstable; urgency=low + + * New upstream release 1.3.1-RC1 + + -- OpenTTD Fri, 17 May 2013 22:00:00 +0200 + +openttd (1.3.0-0) unstable; urgency=low + + * New upstream release 1.3.0 + + -- OpenTTD Mon, 01 Apr 2013 00:00:00 +0200 + +openttd (1.3.0~RC3) unstable; urgency=low + + * New upstream release 1.3.0-RC3 + + -- OpenTTD Mon, 18 Mar 2013 00:00:00 +0100 + +openttd (1.3.0~RC2) unstable; urgency=low + + * New upstream release 1.3.0-RC2 + + -- OpenTTD Tue, 05 Mar 2013 00:00:00 +0100 + +openttd (1.3.0~RC1) unstable; urgency=low + + * New upstream release 1.3.0-RC1 + + -- OpenTTD Tue, 19 Feb 2013 00:00:00 +0100 + +openttd (1.3.0~beta2) unstable; urgency=low + + * New upstream release 1.3.0-beta2 + + -- OpenTTD Thu, 07 Feb 2013 00:00:00 +0100 + +openttd (1.3.0~beta1) unstable; urgency=low + + * New upstream release 1.3.0-beta1 + + -- OpenTTD Mon, 24 Dec 2012 00:00:00 +0100 + +openttd (1.2.3) unstable; urgency=low + + * New upstream release 1.2.3 + + -- OpenTTD Thu, 01 Nov 2012 00:00:00 +0200 + +openttd (1.2.3~RC1) unstable; urgency=low + + * New upstream release 1.2.3-RC1 + + -- OpenTTD Wed, 17 Oct 2012 00:00:00 +0200 + +openttd (1.2.2) unstable; urgency=low + + * New upstream release 1.2.2 + + -- OpenTTD Thu, 16 Aug 2012 20:00:00 +0200 + +openttd (1.2.2~RC1) unstable; urgency=low + + * New upstream release 1.2.2-RC1 + + -- OpenTTD Wed, 01 Aug 2012 00:00:00 +0200 + +openttd (1.2.1) unstable; urgency=low + + * New upstream release 1.2.1 + + -- OpenTTD Fri, 01 Jun 2012 00:00:00 +0200 + +openttd (1.2.1~RC1) unstable; urgency=low + + * New upstream release 1.2.1-RC1 + + -- OpenTTD Wed, 16 Apr 2012 22:00:00 +0200 + +openttd (1.2.0) unstable; urgency=low + + * New upstream release 1.2.0 + + -- OpenTTD Sun, 15 Apr 2012 14:00:00 +0200 + +openttd (1.2.0~RC4) unstable; urgency=low + + * New upstream release 1.2.0-RC4 + + -- OpenTTD Sun, 01 Apr 2012 00:00:00 +0200 + +openttd (1.2.0~RC3) unstable; urgency=low + + * New upstream release 1.2.0-RC3 + + -- OpenTTD Sun, 18 Mar 2012 18:00:00 +0100 + +openttd (1.2.0~RC2) unstable; urgency=low + + * New upstream release 1.2.0-RC2 + + -- OpenTTD Sun, 04 Mar 2012 18:00:00 +0100 + +openttd (1.2.0~RC1) unstable; urgency=low + + * New upstream release 1.2.0-RC1 + + -- OpenTTD Sun, 19 Feb 2012 23:00:00 +0100 + +openttd (1.2.0~beta4) unstable; urgency=low + + * New upstream release 1.2.0-beta4 + + -- OpenTTD Sat, 04 Feb 2012 16:00:00 +0100 + +openttd (1.2.0~beta3) unstable; urgency=low + + * New upstream release 1.2.0-beta3 + + -- OpenTTD Sat, 21 Jan 2012 16:00:00 +0100 + +openttd (1.2.0~beta2) unstable; urgency=low + + * New upstream release 1.2.0-beta2 + + -- OpenTTD Sat, 07 Jan 2012 00:00:00 +0100 + +openttd (1.2.0~beta1) unstable; urgency=low + + * New upstream release 1.2.0-beta1 + + -- OpenTTD Sat, 24 Dec 2011 00:00:00 +0100 + +openttd (1.1.4) unstable; urgency=low + + * New upstream release 1.1.4 + + -- OpenTTD Mon, 05 Dec 2011 00:00:00 +0400 + +openttd (1.1.4-RC1) unstable; urgency=low + + * New upstream release 1.1.4-RC1 + + -- OpenTTD Sun, 20 Nov 2011 17:00:00 +0100 + +openttd (1.1.3) unstable; urgency=low + + * New upstream release 1.1.3 + + -- OpenTTD Thu, 15 Sep 2011 21:00:00 +0200 + +openttd (1.1.3-RC1) unstable; urgency=low + + * New upstream release 1.1.3-RC1 + + -- OpenTTD Sun, 04 Sep 2011 17:00:00 +0200 + +openttd (1.1.2) unstable; urgency=low + + * New upstream release 1.1.2 + + -- OpenTTD Sun, 14 Aug 2011 17:00:00 +0200 + +openttd (1.1.2~RC2) unstable; urgency=low + + * New upstream release 1.1.2-RC2 + + -- OpenTTD Sat, 30 Jul 2011 21:00:00 +0200 + +openttd (1.1.2~RC1) unstable; urgency=low + + * New upstream release 1.1.2-RC1 + + -- OpenTTD Sun, 24 Jul 2011 21:00:00 +0200 + +openttd (1.1.1) unstable; urgency=low + + * New upstream release 1.1.1 + + -- OpenTTD Wed, 01 Jun 2011 00:00:00 +0200 + +openttd (1.1.1~RC1) unstable; urgency=low + + * New upstream release 1.1.1-RC1 + + -- OpenTTD Sun, 15 May 2011 21:00:00 +0200 + +openttd (1.1.0) unstable; urgency=low + + * New upstream release 1.1.0 + + -- OpenTTD Fri, 01 Apr 2011 00:00:00 +0100 + +openttd (1.1.0~RC3) unstable; urgency=low + + * New upstream release 1.1.0-RC3 + + -- OpenTTD Fri, 18 Mar 2011 22:00:00 +0100 + +openttd (1.1.0~RC2) unstable; urgency=low + + * New upstream release 1.1.0-RC2 + + -- OpenTTD Fri, 04 Mar 2011 22:00:00 +0100 + +openttd (1.1.0~RC1) unstable; urgency=low + + * New upstream release 1.1.0-RC1 + + -- OpenTTD Fri, 18 Feb 2011 22:00:00 +0100 + +openttd (1.1.0~beta5) unstable; urgency=low + + * New upstream release 1.1.0-beta5 + + -- OpenTTD Fri, 04 Feb 2011 22:00:00 +0100 + +openttd (1.1.0~beta4) unstable; urgency=low + + * New upstream release 1.1.0-beta4 + + -- OpenTTD Fri, 21 Jan 2011 00:00:00 +0100 + +openttd (1.1.0~beta3) unstable; urgency=low + + * New upstream release 1.1.0-beta3 + + -- OpenTTD Sun, 09 Jan 2011 18:00:00 +0100 + +openttd (1.1.0~beta2) unstable; urgency=low + + * New upstream release 1.1.0-beta2 + + -- OpenTTD Fri, 31 Dec 2010 18:00:00 +0100 + +openttd (1.1.0~beta1) unstable; urgency=low + + * New upstream release 1.1.0-beta1 + + -- OpenTTD Fri, 24 Dec 2010 00:00:00 +0100 + +openttd (1.0.5-0) unstable; urgency=low + + * New upstream release 1.0.5 + + -- OpenTTD Sat, 20 Nov 2010 21:00:00 +0000 + +openttd (1.0.5~rc2-0) unstable; urgency=low + + * New upstream release 1.0.5~rc2 + + -- OpenTTD Sun, 14 Nov 2010 15:00:00 +0000 + +openttd (1.0.5~rc1-0) unstable; urgency=low + + * New upstream release 1.0.5-RC1 + + -- OpenTTD Sun, 31 Oct 2010 15:00:00 +0000 + +openttd (1.0.4-0) unstable; urgency=low + + * New upstream release 1.0.4 + + -- OpenTTD Tue, 14 Sep 2010 20:00:00 +0000 + +openttd (1.0.4~rc1-0) unstable; urgency=low + + * New upstream release 1.0.4-RC1 + + -- OpenTTD Mon, 30 Aug 2010 20:00:00 +0000 + +openttd (1.0.3-0) unstable; urgency=low + + * New upstream release 1.0.3 + + -- OpenTTD Sun, 01 Aug 2010 00:00:00 +0000 + +openttd (1.0.3~rc1-0) unstable; urgency=low + + * New upstream release 1.0.3-RC1 + + -- OpenTTD Sat, 05 Jul 2010 17:37:21 +0000 + +openttd (1.0.2-0) unstable; urgency=low + + * New upstream release 1.0.2 + + -- OpenTTD Sat, 19 Jun 2010 18:36:21 +0000 + +openttd (1.0.2~rc1-0) unstable; urgency=low + + * New upstream release 1.0.2-RC1 + + -- OpenTTD Sat, 05 Jun 2010 23:36:21 +0000 + +openttd (1.0.1-0) unstable; urgency=low + + * New upstream release 1.0.1 + + -- OpenTTD Sat, 01 May 2010 00:00:00 +0200 + +openttd (1.0.1~rc2-0) unstable; urgency=low + + * New upstream release 1.0.1-RC2 + + -- OpenTTD Wed, 21 Apr 2010 21:36:21 +0200 + +openttd (1.0.1~rc1-0) unstable; urgency=low + + * New upstream release 1.0.1-RC1 + + -- OpenTTD Sat, 17 Apr 2010 23:36:21 +0000 + +openttd (1.0.0-1) unstable; urgency=low + + * [30a2162] New upstream release 1.0.0. (Closes: #570104) + * [102698a] Make openttd-wrapper work with older mktemp versions. + + -- Matthijs Kooijman Fri, 02 Apr 2010 23:36:21 +0200 + +openttd (1.0.0~rc3-2) unstable; urgency=low + + * [279c5ef] Recommend openttd-opengfx and suggest openttd-opensfx. + * [9330ad7] Update README.Debian concerning music files. + * [07bde24] Move openttd from contrib to main. (Closes: #560810) + + -- Matthijs Kooijman Thu, 18 Mar 2010 13:16:32 +0100 + +openttd (1.0.0~rc3-1) unstable; urgency=low + + * [412d153] New upstream release 1.0.0~rc3. + + -- Matthijs Kooijman Thu, 18 Mar 2010 10:09:33 +0100 + +openttd (1.0.0~rc2-1) unstable; urgency=low + + * [9c99af4] New upstream release 1.0.0~rc2. + + -- Matthijs Kooijman Thu, 04 Mar 2010 12:22:28 +0100 + +openttd (1.0.0~rc1-1) unstable; urgency=low + + * [fe4eb51] New upstream release 1.0.0~rc1. + * [6aa2be0] Note that the embedded md5 implementation has a different + license. + * [39eb336] Remove lintian override for empty gm directory. + + -- Matthijs Kooijman Fri, 19 Feb 2010 13:00:53 +0100 + +openttd (1.0.0~beta4-1) unstable; urgency=low + + * [6718224] New upstream release 1.0.0~beta4. + * [7b0fa8d] Remove some more docs that we don't want in the package. + * [bb9d744] Use liblzo2 instead of an embedded minilzo version. + * [949c06b] Explicitly disable iconv support. + + -- Matthijs Kooijman Fri, 19 Feb 2010 12:59:27 +0100 + +openttd (0.7.5-4) unstable; urgency=low + + * [174d0b1] Don't use deprecated < in Replaces. + + -- Matthijs Kooijman Mon, 15 Feb 2010 00:35:33 +0100 + +openttd (0.7.5-3) unstable; urgency=low + + * [d12fc5a] Make openttd-data replace openttd (< 0.7.5-2). + (Closes: #569679) + + -- Matthijs Kooijman Sun, 14 Feb 2010 16:56:31 +0100 + +openttd (0.7.5-2) unstable; urgency=low + + [ Matthijs Kooijman ] + * [fbab21d] Switch to source format 3.0 (quilt). + * [85c0c7d] No longer check for (and complain about missing) datafiles + on installation and upgrades. (Closes: #524651, 562574) + * [827eb61] Split the architecture independent data into openttd-data. + (Closes: #492462) + * [6fbd9c7] Update README.Debian. + * [76a5148] Support cross compilation. (Closes: #550951) + * [2005bf8] Simplify the rules file, make debhelper do more stuff. + * [fc0500e] Remove some configure arguments. + * [8ca38bb] Explicitly enable or disable all of the dependencies. + * [e38fb3e] Let the upstream Makefile install documentation. + * [5954fcf] Update the watch file to the new upstream url scheme. + * [7249594] Fix typo in copyright file. + * [660fb61] Bump the Standards-Version to 3.8.4, with no changes + required. + * [f94ab89] Move the packaging git repository to git.debian.org. + + -- Jordi Mallach Tue, 09 Feb 2010 21:40:24 +0100 + +openttd (0.7.5-1) unstable; urgency=high + + * [cdcb73a] Imported Upstream version 0.7.5. This release fixes + CVE-2009-4007. + + -- Matthijs Kooijman Thu, 24 Dec 2009 00:55:45 +0100 + +openttd (0.7.4-1) unstable; urgency=low + + * [a2c297b0] Imported Upstream version 0.7.4 + * [0232a645] Make Debian-specific patches executable. + * [76be04b] Switch the Debian packaging to git. + + -- Matthijs Kooijman Tue, 15 Dec 2009 22:11:52 +0100 + +openttd (0.7.3-1) unstable; urgency=low + + [ Matthijs Kooijman ] + * New upstream release + * Use printf instead of echo -en in openttd-wrapper to make it POSIX + compatible (Closes: #547758). + * Remove three patches that are now included in upstream. + + -- Matthijs Kooijman Thu, 01 Oct 2009 22:52:59 +0200 + +openttd (0.7.2-1) unstable; urgency=low + + [ Matthijs Kooijman ] + * New upstream release + * Bump Standards-Version to 3.8.3, with no changes required. + * Clean up the rules file a bit and add some lintian overrides. + * Explain why openttd is in contrib (Closes: #539381). + * Add the DM-Upload-Allowed control field. + * Re-add dpatch infrastructure. + * Fix the copyright file, since upstream only allows GPLv2, not later + versions. + * Add a section to the copyright file on the different license used by the + "Squirrel" programming language, which is shipped with OpenTTD since + 0.7.0. + * Backport upstream r17226, which removes the deprecated Encoding entry from + the .desktop file. + * Add a wrapper script for openttd, which captures any stderr output and + displays it when openttd returns an error code (Closes: #533557). + * Recommend x11-utils, since we use xmessage for displaying errors. Don't + depend on it, since openttd will still run fine without it, you just won't + see any errors. + * Backport upstream r17227 and r17229, which prevents terminal escape codes + from ending up in the captured error output. + * Backport upstream r17240, which improves stderr output when files are + missing or corrupt. + + -- Jordi Mallach Fri, 21 Aug 2009 15:27:26 +0200 + +openttd (0.7.1-1) unstable; urgency=low + + [ Matthijs Kooijman ] + * New upstream release. + * Link against libicu to enable right-to-left language support. + + -- Jordi Mallach Tue, 09 Jun 2009 21:46:28 +0200 + +openttd (0.7.0-1) unstable; urgency=low + + [ Matthijs Kooijman ] + * New upstream release. + * Remove Debian specific desktop file, upstream provides one now. + * Add debian/watch file. + + [ Jordi Mallach ] + * Bump Standards-Version to 3.8.1, with no changes required. + * Move to debhelper compat 7. Bump Build-Depends accordingly. + * Use dh_prep. + * Add "set -e" to config script. + * Remove a few extra doc files that get installed by upstream Makefile. + * Add more complete copyright information. + + -- Jordi Mallach Wed, 15 Apr 2009 18:22:10 +0200 + +openttd (0.6.3-1) unstable; urgency=low + + [ Matthijs Kooijman ] + * New upstream release. + + [ Jordi Mallach ] + * Add Spanish Debconf template translation, after fixing its corrupted + encoding (thanks, Germana Oliveira, closes: #499214). + + -- Jordi Mallach Thu, 02 Oct 2008 16:59:03 +0200 + +openttd (0.6.2-1) unstable; urgency=low + + * New upstream release. + - Fixes remote crash vulnerability CVE-2008-3547. Closes: #493714 + + -- Matthijs Kooijman Fri, 08 Aug 2008 11:07:05 +0200 + +openttd (0.6.2~rc2-1) experimental; urgency=low + + [ Matthijs Kooijman ] + * New upstream release. + + [ Jordi Mallach ] + * Fix typo in README.Debian (lintian). + * Remove dpatch build-dep and the empty debian/patches dir. + * Don't ignore possible "make distclean" errors. + + -- Jordi Mallach Sat, 26 Jul 2008 01:35:30 +0200 + +openttd (0.6.2~rc1-1) experimental; urgency=low + + [ Matthijs Kooijman ] + * New upstream release. + + -- Jordi Mallach Thu, 24 Jul 2008 16:09:57 +0200 + +openttd (0.6.1-1) unstable; urgency=low + + [ Matthijs Kooijman ] + * New upstream release. + * Remove no_install_personal.dpatch, it is included upstream now. + + -- Jordi Mallach Thu, 05 Jun 2008 00:47:36 +0200 + +openttd (0.6.0-2) unstable; urgency=low + + [ Jordi Mallach ] + * Rename XS-Vcs-* to the official Vcs-* fields. + + [ Matthijs Kooijman ] + * Don't install anything into ~ during make install, this prevented + successful builds on some architectures. Fix imported from upstream. + * Put the homepage in its own Homepage field instead of in the description. + * Bump Standards-Version to 3.7.3 + + -- Jordi Mallach Thu, 03 Apr 2008 00:07:10 +0200 + +openttd (0.6.0-1) unstable; urgency=low + + [ Matthijs Kooijman ] + * New upstream release: + - Adds note about font-configuration for non-latin languages. + Closes: #462604 + * Add .desktop file, provided by Andrea Colangelo. + Closes: #460073 + * Add Finnish Debconf translation, provided by Esko Arajärvi. + Closes: #456956 + + [ Jordi Mallach ] + * Fixes and improvements for the .desktop file according to the spec. + + -- Jordi Mallach Wed, 02 Apr 2008 14:04:40 +0200 + +openttd (0.5.3-1) unstable; urgency=low + + [ Matthijs Kooijman ] + * New upstream release + + -- Jordi Mallach Tue, 18 Sep 2007 12:05:28 +0200 + +openttd (0.5.2-1) unstable; urgency=low + + [ Jordi Mallach ] + * New upstream release. + * Debconf translation updates: + - Catalan. + + [ Christian Perrier ] + * Debconf templates and debian/control reviewed by the debian-l10n- + english team as part of the Smith review project. + Closes: #422183, #419096. + * Debconf translation updates: + - Swedish. Closes: #422780 + - Basque. Closes: #422786 + - Czech. Closes: #422809 + - Galician. Closes: #422831 + - German. Closes: #422908 + - Tamil. Closes: #423079 + - Russian. Closes: #423224 + - Portuguese. Closes: #423413 + - French. Closes: #424436 + - Brazilian Portuguese. Closes: #425585 + - Dutch. Closes: #425707 + + -- Jordi Mallach Sat, 02 Jun 2007 06:24:34 +0200 + +openttd (0.5.1-1) unstable; urgency=low + + [ Matthijs Kooijman ] + * New upstream release + * Add German and Swedish translations (Closes: #420258, #419097) + * Remove bogus fuzzy mark from the Catalan translation + + [ Jordi Mallach ] + * debian/control: add XS-Vcs-Svn and XS-Vcs-Browser fields. + + -- Jordi Mallach Mon, 23 Apr 2007 21:03:06 +0200 + +openttd (0.5.0-2) unstable; urgency=low + + * Upload to Debian. + + -- Jordi Mallach Sun, 11 Mar 2007 14:12:37 +0100 + +openttd (0.5.0-1) unstable; urgency=low + + [ Matthijs Kooijman ] + * New upstream release + + [ Jordi Mallach ] + * Depend on ${misc:Depends}, not debconf directly. + + -- Jordi Mallach Thu, 8 Mar 2007 15:34:54 +0100 + +openttd (0.5.0~rc5-1) unstable; urgency=low + + [ Matthijs Kooijman ] + * New upstream release + * Compile with freetype and fontconfig support. + + [ Jordi Mallach ] + * Convert debconf templates to podebconf. + * Add a Catalan translation. + * Minor packaging cleanups. + + -- Matthijs Kooijman Mon, 12 Feb 2007 09:25:41 +0100 + +openttd (0.5.0~rc4-1) unstable; urgency=low + + * New upstream release + + -- Matthijs Kooijman Thu, 18 Jan 2007 21:17:28 +0100 + +openttd (0.5.0~rc3-1) unstable; urgency=low + + * New upstream release + + -- Matthijs Kooijman Thu, 18 Jan 2007 20:21:04 +0100 + +openttd (0.5.0~rc2-1) unstable; urgency=low + + * New upstream release + * Removed fix for empty scenarios dir, openttd Makefile now properly handles + this. + + -- Matthijs Kooijman Sun, 31 Dec 2006 12:24:37 +0100 + +openttd (0.5.0~rc1-1) unstable; urgency=low + + * New upstream release. + + -- Matthijs Kooijman Fri, 22 Dec 2006 11:03:46 +0100 + +openttd (0.4.8-1) unstable; urgency=low + + * New upstream release + * Bump standards version to 3.7.2 + + -- Matthijs Kooijman Mon, 14 Aug 2006 16:28:50 +0200 + +openttd (0.4.7-1) unstable; urgency=low + + * New upstream release. + + -- Matthijs Kooijman Mon, 27 Mar 2006 23:40:00 +0200 + +openttd (0.4.6-1) unstable; urgency=low + + * New upstream release. + * Remove old terminal messages and make sure that debconf is always called. + + -- Matthijs Kooijman Wed, 8 Mar 2006 23:57:35 +0100 + +openttd (0.4.5-1) unstable; urgency=low + + * New upstream release + * Bump Standards-Version to 3.6.2 + * s/timdity/timidity/ in README.Debian. + * Use debconf for prompting instead of terminal. + * Fix makefile to create icon dir if necessary. + * Fix syntax error in manpage. + + -- Matthijs Kooijman Wed, 1 Feb 2006 01:56:39 +0100 + +openttd (0.4.0.1-5) unstable; urgency=low + + * Fixed capitalization of menu item. + * Install xpm icon to /usr/share/pixmaps and don't install png icon, since + it is not used. + + -- Matthijs Kooijman Thu, 22 Sep 2005 10:35:09 +0200 + +openttd (0.4.0.1-4) unstable; urgency=low + + * Changelog was distributed twice. + * Put openttd in contrib. + + -- Matthijs Kooijman Mon, 19 Sep 2005 23:49:18 +0200 + +openttd (0.4.0.1-3) unstable; urgency=low + + * Clarified installing instructions in README.Debian + + -- Matthijs Kooijman Thu, 16 Jun 2005 03:51:13 +0200 + +openttd (0.4.0.1-2) unstable; urgency=low + + * Added Suggests: timidity, freepats + + -- Matthijs Kooijman Thu, 16 Jun 2005 03:34:03 +0200 + +openttd (0.4.0.1-1) unstable; urgency=low + + * New upstream release + + -- Matthijs Kooijman Mon, 23 May 2005 13:04:24 +0200 + +openttd (0.4.0-1) unstable; urgency=low + + * New upstream release + + -- Matthijs Kooijman Mon, 16 May 2005 00:16:17 +0200 + +openttd (0.3.6-1) unstable; urgency=low + + * New upstream release + * Modifed Makefile to install xpm icon and scenarios in /usr/share/games/openttd/ + * Added openttd.32.xpm, openttd.64.xpm was too big + + -- Matthijs Kooijman Tue, 25 Jan 2005 19:21:08 +0100 + +openttd (0.3.5-2) unstable; urgency=low + + * Fixed some lintian warnings. + * Added openttd.64.xpm (icon for menu). + + -- Matthijs Kooijman Mon, 27 Dec 2004 01:51:36 +0100 + +openttd (0.3.5-1) unstable; urgency=low + + * Initial Release. + + -- Matthijs Kooijman Fri, 24 Dec 2004 02:58:47 +0100 + diff --git a/os/debian/compat b/os/debian/compat new file mode 100644 index 0000000..7f8f011 --- /dev/null +++ b/os/debian/compat @@ -0,0 +1 @@ +7 diff --git a/os/debian/control b/os/debian/control new file mode 100644 index 0000000..54e14ce --- /dev/null +++ b/os/debian/control @@ -0,0 +1,36 @@ +Source: openttd +Section: games +Priority: optional +Maintainer: Matthijs Kooijman +Uploaders: Jordi Mallach +Build-Depends: debhelper (>= 7.0.50), libsdl-dev, zlib1g-dev, libpng-dev, libfreetype6-dev, libfontconfig-dev, libicu-dev, liblzma-dev, liblzo2-dev +Standards-Version: 3.8.4 +Vcs-Browser: http://anonscm.debian.org/gitweb/?p=collab-maint/openttd.git +Vcs-Git: git://anonscm.debian.org/collab-maint/openttd.git +Homepage: http://www.openttd.org/ + +Package: openttd +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Recommends: openttd-opengfx, x11-utils +Replaces: openttd-data +Conflicts: openttd-data +Suggests: openttd-opensfx, timidity, freepats +Description: reimplementation of Transport Tycoon Deluxe with enhancements + OpenTTD is a reimplementation of the Microprose game "Transport + Tycoon Deluxe" with lots of new features and enhancements. + . + OpenTTD is playable with the free graphics files from the openttd-opengfx + package and optional sound files from the openttd-opensfx package (which is in + non-free). Alternatively, OpenTTD can use the graphics files from the original + Transport Tycoon Deluxe game (See README.Debian on how to set this up). + +Package: openttd-dbg +Architecture: any +Section: debug +Priority: extra +Depends: openttd (= ${binary:Version}), ${misc:Depends} +Description: debugging symbols for openttd + This package contains the debugging symbols for OpenTTD, the reimplementation + of the Micropose game "Transport Tycoon Deluxe" with lots of new features and + enhancements. diff --git a/os/debian/copyright b/os/debian/copyright new file mode 100644 index 0000000..be573b4 --- /dev/null +++ b/os/debian/copyright @@ -0,0 +1,106 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: OpenTTD +Upstream-Contact: info@openttd.org, #openttd on irc.oftc.net +Source: http://www.openttd.org + + +Files: * +Copyright: © 2004-2012 Ludvig Strigeous and others. +License: GPL-2.0 + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2.0 as + published by the Free Software Foundation; + . + 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 package; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + . + On Debian systems, the complete text of the GNU General Public License + version 2 can be found in `/usr/share/common-licenses/GPL-2'. + +Files: src/3rdparty/squirrel/* +Copyright: © 2003-2009 Alberto Demichelis +License: Zlib + +Files: src/3rdparty/md5/* +Copyright: © 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. +License: Zlib + + +License: Zlib + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + . + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + . + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software in + a product, an acknowledgment in the product documentation would be + appreciated but is not required. + . + 2. Altered source versions must be plainly marked as such, and must not + be misrepresented as being the original software. + . + 3. This notice may not be removed or altered from any source + distribution. + +Files: os/dos/exe2coff/* +Copyright: © 1998 DJ Delorie +License: GPL-2.0 with additional restrictions + This document is Copyright (C) DJ Delorie and may be distributed + verbatim, but changing it is not allowed. + . + Source code copyright DJ Delorie is distributed under the terms of the + GNU General Public Licence, with the following exceptions: + . + * Sources used to build crt0.o, gcrt0.o, libc.a, libdbg.a, and + libemu.a are distributed under the terms of the GNU Library General + Public License, rather than the GNU GPL. + . + * Any existing copyright or authorship information in any given source + file must remain intact. If you modify a source file, a notice to that + effect must be added to the authorship information in the source file. + . + * Runtime binaries, as provided by DJ in DJGPP, may be distributed + without sources ONLY if the recipient is given sufficient information + to obtain a copy of djgpp themselves. This primarily applies to + go32-v2.exe, emu387.dxe, and stubedit.exe. + . + * Runtime objects and libraries, as provided by DJ in DJGPP, when + linked into an application, may be distributed without sources ONLY + if the recipient is given sufficient information to obtain a copy of + djgpp themselves. This primarily applies to crt0.o and libc.a. + . + On Debian systems, the complete text of the GNU General Public License + version 2 can be found in `/usr/share/common-licenses/GPL-2'. +Comment: + Given only the exe2coff.c file is distributed in the source distribution (and + nothing in Debian binary distribution), it seems only the 2nd condition + applies. + +Files: os/dos/cwsdpmi/* +Source: http://homer.rice.edu/~sandmann/cwsdpmi/index.html +Copyright: © 1995-2000 Charles W Sandmann (sandmann@clio.rice.edu) +License: Custom binary-only license + This is release 5. The files in this binary distribution may be redistributed + under the GPL (with source) or without the source code provided: + . + * CWSDPMI.EXE or CWSDPR0.EXE are not modified in any way except via CWSPARAM. + . + * CWSDSTUB.EXE internal contents are not modified in any way except via + CWSPARAM or STUBEDIT. It may have a COFF image plus data appended to it. + . + * Notice to users that they have the right to receive the source code and/or + binary updates for CWSDPMI. Distributors should indicate a site for the + source in their documentation. +Comment: + Files are distributed as binary only, so the second option in the license + ("without source code provided: ...") is applicable. diff --git a/os/debian/gbp.conf b/os/debian/gbp.conf new file mode 100644 index 0000000..58b68d3 --- /dev/null +++ b/os/debian/gbp.conf @@ -0,0 +1,13 @@ +[DEFAULT] +# Use pristine-tar +pristine-tar = True + +[git-dch] +# We use metaheaders in commit messages. +meta = True +# Put git commit ids in the debian changelog. +id-length = 7 + +[git-import-orig] +# Use a custom commit message for upstream imports. +import-msg = New upstream release %(version)s. diff --git a/os/debian/menu b/os/debian/menu new file mode 100644 index 0000000..3afa6e0 --- /dev/null +++ b/os/debian/menu @@ -0,0 +1,2 @@ +?package(openttd):needs="X11" section="Games/Simulation" title="OpenTTD"\ +command="/usr/games/openttd" icon="/usr/share/pixmaps/openttd.32.xpm" diff --git a/os/debian/openttd-wrapper b/os/debian/openttd-wrapper new file mode 100644 index 0000000..6f85f00 --- /dev/null +++ b/os/debian/openttd-wrapper @@ -0,0 +1,28 @@ +#!/bin/sh +# This is a wrapper script that checks openttd's exit status and +# displays its stderr output + +# Get a file to capture stderr to. Use the deprecated -t option, so this +# works on the old mktemp from the mktemp package (which has been +# replaced by the version from the coreutils package). +TMPFILE=`mktemp -t openttd.errout.XXXXXXXXX` + +if [ ! -w "$TMPFILE" ]; then + xmessage "Could not create temporary file for error messages. Not starting OpenTTD." + exit 1; +fi + +# Capture stderr +openttd "$@" 2> "$TMPFILE" +ERRCODE=$? +if [ "$ERRCODE" -ne 0 ]; then + CODEMSG="OpenTTD returned with error code $ERRCODE." + if [ -s "$TMPFILE" ]; then + MESSAGE="$CODEMSG The following error messages were produced:\n\n" + printf "$MESSAGE" | cat - "$TMPFILE" | fold -s | xmessage -file - + else + xmessage "$CODEMSG No error messages were produced." + fi +fi + +rm -f "$TMPFILE" diff --git a/os/debian/patches/run-openttd-wrapper.patch b/os/debian/patches/run-openttd-wrapper.patch new file mode 100644 index 0000000..ff8fc15 --- /dev/null +++ b/os/debian/patches/run-openttd-wrapper.patch @@ -0,0 +1,20 @@ +From: Matthijs Kooijman +Subject: Use a wrapper script for running openttd + +The wrapper script captures stderr from openttd and displays this in +case of an error. This patch makes the the .desktop file call the +wrapper instead of the openttd binary directly. + +Index: media/openttd.desktop.in +=================================================================== +--- a/media/openttd.desktop.in (revision 20124) ++++ b/media/openttd.desktop.in (working copy) +@@ -5,7 +5,7 @@ + Version=1.1 + Name=!!MENU_NAME!! + Icon=openttd +-Exec=!!TTD!! ++Exec=/usr/share/games/openttd/openttd-wrapper + Terminal=false + Categories=!!MENU_GROUP!! + Comment=A clone of Transport Tycoon Deluxe diff --git a/os/debian/patches/series b/os/debian/patches/series new file mode 100644 index 0000000..f7cf2d9 --- /dev/null +++ b/os/debian/patches/series @@ -0,0 +1 @@ +run-openttd-wrapper.patch diff --git a/os/debian/rules b/os/debian/rules new file mode 100755 index 0000000..dfd3925 --- /dev/null +++ b/os/debian/rules @@ -0,0 +1,50 @@ +#!/usr/bin/make -f +# -*- makefile -*- +# Makefile to build the openttd debian package. + +# Use debhelper default for all targets (but some are overridden below). +%: + dh --parallel $@ + +DEB_HOST_GNU_TYPE=$(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +DEB_BUILD_GNU_TYPE=$(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) +ifneq ($(DEB_HOST_GNU_TYPE),$(DEB_BUILD_GNU_TYPE)) +CROSS= --build $(DEB_BUILD_GNU_TYPE) --host $(DEB_HOST_GNU_TYPE) +endif + +# This prevents linking uselessly to libicudata and silences a warning +# in the build process. +DEB_LDFLAGS_MAINT_APPEND="-Wl,-as-needed" + +# Enable all hardening options (since openttd offers a network-listening +# service that handles untrusted data). +DEB_BUILD_MAINT_OPTIONS=hardening=+all + +# Load buildflags (this uses dpkg-buildflags). Note that we don't export +# them, but instead pass them to ./configure explicitly. +include /usr/share/dpkg/buildflags.mk + +# Pass custom options to configure. Since it's not autoconf but a custom +# script, some of the option names are slightly different. We also need +# to be explicit about the dependencies, in case we're not running in a +# clean build root. +override_dh_auto_configure: + ./configure $(CROSS) --prefix-dir=/usr --install-dir=debian/openttd --without-allegro --with-zlib --with-sdl --with-png --with-freetype --with-fontconfig --with-icu --with-liblzo2 --with-lzma --without-xdg-basedir --without-iconv --disable-strip CFLAGS="$(CFLAGS) $(CPPFLAGS)" CXXFLAGS="$(CXXFLAGS) $(CPPFLAGS)" LDFLAGS="$(LDFLAGS)" CFLAGS_BUILD="$(CFLAGS) $(CPPFLAGS)" CXXFLAGS_BUILD="$(CXXFLAGS) $(CPPFLAGS)" LDFLAGS_BUILD="$(LDFLAGS)" + +# Do some extra installation +override_dh_auto_install: + $(MAKE) install DO_NOT_INSTALL_CHANGELOG=1 DO_NOT_INSTALL_LICENSE=1 + +# Don't do testing. Because the OpenTTD Makefile always does dependency +# generation (even on invalid targets), dh_auto_test thinks there is a +# "test" target, while there isn't. +override_dh_auto_test: + +# Call mrproper. Again, dh_auto_clean thinks there is a distclean +# target, while there isn't. +override_dh_auto_clean: + [ ! -f Makefile ] || $(MAKE) mrproper + +# We want to strip the debug informatiton into the -dbg package. +override_dh_strip: + dh_strip --dbg-package=openttd-dbg diff --git a/os/debian/source/format b/os/debian/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/os/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/os/debian/watch b/os/debian/watch new file mode 100644 index 0000000..776381b --- /dev/null +++ b/os/debian/watch @@ -0,0 +1,5 @@ +version=3 + +options=downloadurlmangle=s/(.*)\/index.html$/\1\/openttd-\1-source.tar.gz/ \ +http://master.binaries.openttd.org/releases/ \ +(\d+(?:\.\d+)*)/index.html diff --git a/os/dos/cwsdpmi/README.licensing b/os/dos/cwsdpmi/README.licensing new file mode 100644 index 0000000..112b02a --- /dev/null +++ b/os/dos/cwsdpmi/README.licensing @@ -0,0 +1,3 @@ +The files in this directory are not licensed under the same terms as the +rest of OpenTTD. Licensing details can be found in OpenTTD's readme.txt +and in this directory or subdirectories as well. diff --git a/os/dos/cwsdpmi/cwsdpmi.exe b/os/dos/cwsdpmi/cwsdpmi.exe new file mode 100644 index 0000000..17e3220 Binary files /dev/null and b/os/dos/cwsdpmi/cwsdpmi.exe differ diff --git a/os/dos/cwsdpmi/cwsdpmi.txt b/os/dos/cwsdpmi/cwsdpmi.txt new file mode 100644 index 0000000..14b09c4 --- /dev/null +++ b/os/dos/cwsdpmi/cwsdpmi.txt @@ -0,0 +1,173 @@ +CWSDPMI is Copyright (C) 1995-2000 Charles W Sandmann (sandmann@clio.rice.edu) + 1206 Braelinn, Sugar Land, TX 77479 + +This is release 5. The files in this binary distribution may be redistributed +under the GPL (with source) or without the source code provided: + +* CWSDPMI.EXE or CWSDPR0.EXE are not modified in any way except via CWSPARAM. + +* CWSDSTUB.EXE internal contents are not modified in any way except via + CWSPARAM or STUBEDIT. It may have a COFF image plus data appended to it. + +* Notice to users that they have the right to receive the source code and/or + binary updates for CWSDPMI. Distributors should indicate a site for the + source in their documentation. + +------------------------------------------------------------------------------- + +CWSDPMI was written to provide DPMI services for V2 of DJGPP. It currently +does not support 16-bit DPMI applications, or DPMI applications requiring a +built in extender. It does support virtual memory and hardware interrupt +reflection from real mode to protected mode. DJGPP V1.1x and RSX applications +will also run using this server, which can be used to provide enhanced control +over hardware interrupts. Some DPMI 1.0 extensions (0x506, 0x507, 0x508) have +been implemented. + +CWSDPR0.EXE is an alternate version which runs at ring 0 with virtual memory +disabled. It may be used if access to ring-0 features are desired. It +currently does not switch stacks on HW interrupts, so some DJGPP features +such as SIGINT and SIGFPE are not supported and will generate a double fault +or stack fault error (to be fixed someday). + +CWSDSTUB.EXE is a stub loader image for DJGPP which includes CWSDPMI. This +allows single executable image distributions. You can use the EXE2COFF +program and COPY /B CWSDSTUB.EXE+yourimage yourimage.exe to create a +standalone executable image. + +Some of the internal tuning and configuration parameters may be modified +in the image using CWSPARAM.EXE (see CWSPARAM.DOC). + +If you want to use CWSDPMI with DJGPP, you expand the distribution into the +DJGPP directory tree. CWSDPMI.EXE will be put in the BIN directory with your +DJGPP images and it will automatically be loaded when they run. + +Directions for use (server can be used in either of two different ways): + +1) "cwsdpmi" alone with no parameters will terminate and stay resident + FOR A SINGLE DPMI PROCESS. This means it unloads itself when your + DPMI application exits. This mode is useful in software which needs + DPMI services, since CWSDPMI can be exec'ed and then will unload on exit. + +2) "cwsdpmi -p" will terminate and stay resident until you remove it. + It can be loaded into UMBs with LH. "cwsdpmi -u" will unload the TSR. + +3) The file used for virtual memory swapping, if desired, is controlled + by the "-sc:\cwsdpmi.swp" syntax on the command line. You must specify + either a file with full disk/directory syntax, or "-s-" which disables + virtual memory. + +4) The default swap file name is c:\cwsdpmi.swp, but this can be changed + with the CWSPARAM image, as can some other parameters. + +5) You can disable the DPMI 1.0 extensions by starting the image with the + "cwsdpmi -x" syntax. This feature allows you to run programs developed + under other DPMI providers which do not behave properly with these + extensions enabled (typically use of NULL pointers). + +I would like to give special thanks to DJ Delorie who wrote the original +GO32 code on which CWSDPMI is based. Morten Welinder also provided and +improved much of the code in this program. + +------------------------------------------------------------------------------- + +This section contains a list of the error messages you might see out of +CWSDPMI and some details on what they mean. + +Exceptions are only handled by CWSDPMI if the application does not establish +an exception handler, exceptions nest 5 deep, or the error is particularly bad: + +"Page fault" - + 1) an illegal page fault happens in a RMCB or HW interrupt, (lock all pages!) + 2) all available pages have been locked, + 3) the application is using non-committed pages for null pointer protection. +"Double Fault" - multiple exceptions occurred +"Invalid TSS" - typically due to RMCB or HW interrupt being called after the + selectors/memory have been deallocated (remember to reset the mouse) +"General Protection Fault" - bad parameter sent to a DPMI call + +"80386 required." + +Since 80286 and lesser processors don't have the hardware necessary to +run CWSDPMI. No workaround, upgrade. + +"DOS 3 required." + +A few interrupts are used which need DOS 3.0 or higher. I don't expect to +ever see this message, since 80386 machines were introduced after DOS 3.0 +and that check is made first. + +"CWSDPMI V0.90+ (r5) Copyright (C) 2000 CW Sandmann ABSOLUTELY NO WARRANTY" + +An informational message displayed if the program is not run in one-pass mode. + +"Protected mode not accessible." + +This message should only be displayed if running CWSDPMI in a protected +environment with no access to protected mode. In this case, DPMI should +already be available and CWSDPMI would not be needed. This might happen if +a 16-bit DPMI client is loaded and a DJGPP image attempts to load CWSDPMI +to provide 32-bit DPMI services under Windows. + +"Warning: cannot open swap file c:\cwsdpmi.swp" + +Maybe you are out of file handles, or the swap file name is incorrectly +specified in the image (change the name with cwsparam). + +"No swap space!" + +This message means you tried to use more paging file than CWSDPMI was +configured to handle. Since this is protected against in the memory +allocation code, you should never see this message. + +"Swap disk full!" + +This means the paging file could not be expanded when trying to page +memory out to disk. This would normally not be seen, unless you are +writing output to the same disk which holds the paging file. Decrease +the amount of memory your DPMI application is using or free up disk space. + +"Interrupt 0x??" + +Your application tried to call an interrupt from protected mode which +normally shouldn't be called (something like a data pointer). If the +request was allowed to continue it would likely hang your machine. If you +see this message and think the interrupt should be allowed to continue, let +me know. + +"Error: Using XMS switched CPU into V86 mode." + +This message might be seen if you have your memory manager in AUTO mode. The +only workaround in this case is to stop using AUTO mode. + +"Error: could not allocate page table memory" + +The page table memory (a minimum of 16Kb) is allocated from conventional +memory (either in the 640Kb region or UMBs). If CWSDPMI cannot allocate the +minimum necessary memory, you would see this message. Free up some +conventional memory. You may also see this message if a page directory needs +to be faulted in, and there are no available pages. This means too many pages +have been locked for the allocated page tables available. While CWSDPMI +tries to dynamically allocate these if needed, this effort failed. You need +to increase the number of page tables with CWSPARAM, or increase the amount +of free conventional memory if it is low. If the application which calls +CWSDPMI internally manages all the DOS memory, the page tables may need to +be pre-allocated at DPMI startup time (if this is needed, try using the +run option flag 2 in cwsparam). + +"16-bit DPMI unsupported." + +CWSDPMI is a 32-bit only DPMI server. Ideally, on the request to enter DPMI's +PM with a 16-bit request, we would just fail the call setting the carry bit +like the DPMI specification describes. Some buggy 16-bit compiler tools don't +check the return status and will hang the machine in this case. So, I issue +an error message and exit the image instead. + +"Descriptors exhausted." + +An attempt to nest a DPMI client failed in the setup phase due to insufficient +free selectors in the LDT. + +"CWSDPMI not removed" + +When the -u parameter is specified, if DPMI is not detected this message is +printed. Informational. diff --git a/os/dos/cwsdpmi/cwsdstub.exe b/os/dos/cwsdpmi/cwsdstub.exe new file mode 100644 index 0000000..fabaf3b Binary files /dev/null and b/os/dos/cwsdpmi/cwsdstub.exe differ diff --git a/os/dos/exe2coff/README.licensing b/os/dos/exe2coff/README.licensing new file mode 100644 index 0000000..112b02a --- /dev/null +++ b/os/dos/exe2coff/README.licensing @@ -0,0 +1,3 @@ +The files in this directory are not licensed under the same terms as the +rest of OpenTTD. Licensing details can be found in OpenTTD's readme.txt +and in this directory or subdirectories as well. diff --git a/os/dos/exe2coff/copying b/os/dos/exe2coff/copying new file mode 100644 index 0000000..a43ea21 --- /dev/null +++ b/os/dos/exe2coff/copying @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/os/dos/exe2coff/copying.dj b/os/dos/exe2coff/copying.dj new file mode 100644 index 0000000..8a55047 --- /dev/null +++ b/os/dos/exe2coff/copying.dj @@ -0,0 +1,48 @@ +This is the file "copying.dj". It does NOT apply to any sources or +binaries copyrighted by UCB Berkeley, the Free Software Foundation, or +any other agency besides DJ Delorie and others who have agreed to +allow their sources to be distributed under these terms. + + Copyright Information for sources and executables that are marked + Copyright (C) DJ Delorie + 7 Kim Lane + Rochester NH 03867-2954 + +This document is Copyright (C) DJ Delorie and may be distributed +verbatim, but changing it is not allowed. + +Source code copyright DJ Delorie is distributed under the terms of the +GNU General Public Licence, with the following exceptions: + +* Sources used to build crt0.o, gcrt0.o, libc.a, libdbg.a, and + libemu.a are distributed under the terms of the GNU Library General + Public License, rather than the GNU GPL. + +* Any existing copyright or authorship information in any given source + file must remain intact. If you modify a source file, a notice to that + effect must be added to the authorship information in the source file. + +* Runtime binaries, as provided by DJ in DJGPP, may be distributed + without sources ONLY if the recipient is given sufficient information + to obtain a copy of djgpp themselves. This primarily applies to + go32-v2.exe, emu387.dxe, and stubedit.exe. + +* Runtime objects and libraries, as provided by DJ in DJGPP, when + linked into an application, may be distributed without sources ONLY + if the recipient is given sufficient information to obtain a copy of + djgpp themselves. This primarily applies to crt0.o and libc.a. + +----- + +Changes to source code copyright BSD, FSF, or others, by DJ Delorie +fall under the terms of the original copyright. Such files usually +have multiple copyright notices in them. + +A copy of the files "COPYING" and "COPYING.LIB" are included with this +document. If you did not receive a copy of these files, you may +obtain one from whence this document was obtained, or by writing: + + Free Software Foundation + 59 Temple Place - Suite 330 + Boston, MA 02111-1307 + USA diff --git a/os/dos/exe2coff/copying.lib b/os/dos/exe2coff/copying.lib new file mode 100644 index 0000000..bbe3fe1 --- /dev/null +++ b/os/dos/exe2coff/copying.lib @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, 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 library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, 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 companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/os/dos/exe2coff/exe2coff.c b/os/dos/exe2coff/exe2coff.c new file mode 100644 index 0000000..aa072e8 --- /dev/null +++ b/os/dos/exe2coff/exe2coff.c @@ -0,0 +1,94 @@ +/* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */ +/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ +/* Updated 2008 to use fread/fopen and friends instead of read/open so it compiles with GCC on Unix (Rubidium) */ +#include +#include +#include +#include +#include +#include +#include + + +static void +exe2aout(char *fname) +{ + unsigned short header[3]; + FILE *ifile; + FILE *ofile; + char buf[4096]; + int rbytes; + char *dot = strrchr(fname, '.'); + if (!dot || strlen(dot) != 4 + || tolower(dot[1]) != 'e' + || tolower(dot[2]) != 'x' + || tolower(dot[3]) != 'e') + { + fprintf(stderr, "%s: Arguments MUST end with a .exe extension\n", fname); + return; + } + + ifile = fopen(fname, "rb"); + if (!ifile) + { + perror(fname); + return; + } + fread(header, sizeof(header), 1, ifile); + if (header[0] == 0x5a4d) + { + long header_offset = (long)header[2]*512L; + if (header[1]) + header_offset += (long)header[1] - 512L; + fseek(ifile, header_offset, SEEK_SET); + header[0] = 0; + fread(header, sizeof(header), 1, ifile); + if ((header[0] != 0x010b) && (header[0] != 0x014c)) + { + fprintf(stderr, "`%s' does not have a COFF/AOUT program appended to it\n", fname); + return; + } + fseek(ifile, header_offset, SEEK_SET); + } + else + { + fprintf(stderr, "`%s' is not an .EXE file\n", fname); + return; + } + + *dot = 0; + ofile = fopen(fname, "w+b"); + if (!ofile) + { + perror(fname); + return; + } + + while ((rbytes=fread(buf, 1, 4096, ifile)) > 0) + { + int wb = fwrite(buf, 1, rbytes, ofile); + if (wb < 0) + { + perror(fname); + break; + } + if (wb < rbytes) + { + fprintf(stderr, "`%s': disk full\n", fname); + exit(1); + } + } + fclose(ifile); + fclose(ofile); +} + +int +main(int argc, char **argv) +{ + int i; + if (argc == 1) printf("Usage: %s ", argv[0]); + for (i=1; i binary.exe || exit +mv binary.exe $1 +rm binary exe2coff/exe2coff diff --git a/os/macosx/openttd.icns b/os/macosx/openttd.icns new file mode 100644 index 0000000..5b8db48 Binary files /dev/null and b/os/macosx/openttd.icns differ diff --git a/os/macosx/plistgen.sh b/os/macosx/plistgen.sh new file mode 100755 index 0000000..b6116d9 --- /dev/null +++ b/os/macosx/plistgen.sh @@ -0,0 +1,48 @@ +#!/bin/sh + +# $Id$ + +# sets VERSION to the value if RELEASE if there are any, +# otherwise it sets VERSION to revision number +if [ "$3" ]; then +VERSION="$3" +else +VERSION="$2" +fi +date=`date +%Y` + +# Generates Info.plist while applying $VERSION + +echo " + + + CFBundleDevelopmentRegion + English + CFBundleDisplayName + OpenTTD + CFBundleExecutable + openttd + CFBundleGetInfoString + $VERSION, Copyright 2004-$date The OpenTTD team + CFBundleIconFile + openttd.icns + CFBundleIdentifier + org.openttd.openttd + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + OpenTTD + CFBundlePackageType + APPL + CFBundleShortVersionString + $VERSION + CFBundleVersion + $VERSION + NSHumanReadableCopyright + Copyright 2004-$date The OpenTTD team + NSPrincipalClass + NSApplication + +" > "$1"/Contents/Info.plist diff --git a/os/macosx/splash.png b/os/macosx/splash.png new file mode 100644 index 0000000..e67d10d Binary files /dev/null and b/os/macosx/splash.png differ diff --git a/os/morphos/icons/OpenTTD.info b/os/morphos/icons/OpenTTD.info new file mode 100644 index 0000000..3a25be6 Binary files /dev/null and b/os/morphos/icons/OpenTTD.info differ diff --git a/os/morphos/icons/docs.info b/os/morphos/icons/docs.info new file mode 100644 index 0000000..6f8ac00 Binary files /dev/null and b/os/morphos/icons/docs.info differ diff --git a/os/morphos/icons/document.info b/os/morphos/icons/document.info new file mode 100644 index 0000000..877ea35 Binary files /dev/null and b/os/morphos/icons/document.info differ diff --git a/os/morphos/icons/drawer.info b/os/morphos/icons/drawer.info new file mode 100644 index 0000000..149ef7e Binary files /dev/null and b/os/morphos/icons/drawer.info differ diff --git a/os/os2/build_lang.cmd b/os/os2/build_lang.cmd new file mode 100644 index 0000000..57d3e99 --- /dev/null +++ b/os/os2/build_lang.cmd @@ -0,0 +1,8 @@ +rem +rem Building language files... +rem +cd .. +strgen\strgen +for %%f in (lang\*.txt) do strgen\strgen %%f +cd strgen + diff --git a/os/os2/dedicated.cmd b/os/os2/dedicated.cmd new file mode 100644 index 0000000..f4eb524 --- /dev/null +++ b/os/os2/dedicated.cmd @@ -0,0 +1 @@ +start /n /win openttd.exe -D %1 %2 %3 %4 %5 %6 %7 %8 %9 diff --git a/os/os2/installer/download_nosound.cmd b/os/os2/installer/download_nosound.cmd new file mode 100644 index 0000000..39e9843 --- /dev/null +++ b/os/os2/installer/download_nosound.cmd @@ -0,0 +1,21 @@ +@echo off +if "%1" == "" goto err +if "%2" == "" goto err + +echo Downloading NoSound... + +%1\wget http://binaries.openttd.org/installer/nosound-NOSOUND_VERSION.7z -O %2/baseset/nosound.7z + +echo Extracting NoSound... + +%1\7za x -y -O%2/baseset %2/baseset/nosound.7z +del %1\baseset\nosound.7z /n + +echo NoSound has been installed. +goto end + +:err +echo This batch file is only intended for use by the OpenTTD installer. +echo Please visit www.openttd.org for details on downloading NoSound. + +:end \ No newline at end of file diff --git a/os/os2/installer/download_opengfx.cmd b/os/os2/installer/download_opengfx.cmd new file mode 100644 index 0000000..c2686b4 --- /dev/null +++ b/os/os2/installer/download_opengfx.cmd @@ -0,0 +1,21 @@ +@echo off +if "%1" == "" goto err +if "%2" == "" goto err + +echo Downloading OpenGFX... + +%1\wget http://binaries.openttd.org/installer/opengfx-OPENGFX_VERSION.7z -O %2/baseset/opengfx.7z + +echo Extracting OpenGFX... + +%1\7za x -y -O%2/baseset %2/baseset/opengfx.7z +del %1\baseset\opengfx.7z /n + +echo OpenGFX has been installed. +goto end + +:err +echo This batch file is only intended for use by the OpenTTD installer. +echo Please visit www.openttd.org for details on downloading OpenGFX. + +:end diff --git a/os/os2/installer/download_opensfx.cmd b/os/os2/installer/download_opensfx.cmd new file mode 100644 index 0000000..0a46dea --- /dev/null +++ b/os/os2/installer/download_opensfx.cmd @@ -0,0 +1,21 @@ +@echo off +if "%1" == "" goto err +if "%2" == "" goto err + +echo Downloading OpenSFX... + +%1\wget http://binaries.openttd.org/installer/opensfx-OPENSFX_VERSION.7z -O %2/baseset/opensfx.7z + +echo Extracting OpenSFX... + +%1\7za x -y -O%2/baseset %2/baseset/opensfx.7z +del %1\baseset\opensfx.7z /n + +echo OpenSFX has been installed. +goto end + +:err +echo This batch file is only intended for use by the OpenTTD installer. +echo Please visit www.openttd.org for details on downloading OpenSFX. + +:end diff --git a/os/os2/installer/make_installer.cmd b/os/os2/installer/make_installer.cmd new file mode 100644 index 0000000..289b6ea --- /dev/null +++ b/os/os2/installer/make_installer.cmd @@ -0,0 +1,85 @@ +@echo off + +set OPENTTD_VERSION=1.5.0 +set OPENSFX_VERSION=0.8.0 +set NOSOUND_VERSION=0.8.0 +set OPENGFX_VERSION=1.2.0 + +echo To make the installer, you must have the WarpIN compiler (wic) installed and in +echo your path, as well as wget and unzip. This file will download the various DLLs +echo to be distributed with the installer. If you do not want to continue, please +echo press CTRL-C now. +echo. +pause + +cd ..\..\..\bundle + +if not exist SDL12.dll goto getsdl +if not exist FSLib.dll goto getsdl +goto libc + +:getsdl + +wget http://www.os2site.com/sw/dev/sdl/sdl-1.2.10-bin-20080804.zip -O dl.zip +unzip -j dl.zip SDL/FSLib.dll SDL/SDL12.dll +del dl.zip + +:libc + +if exist libc063.dll goto gcc + +wget ftp://ftp.netlabs.org/pub/gcc/libc-0.6.3-csd3.zip -O dl.zip +unzip -j dl.zip libc063.dll +del dl.zip + +:gcc + +if exist gcc442.dll goto tools + +wget http://www.owenrudge.net/various/gcc442.zip -O dl.zip +unzip -j dl.zip gcc442.dll +del dl.zip + +:tools + +cd ..\os\os2\installer +if exist tools goto opengfx + +mkdir tools +cd tools + +wget http://download.smedley.info/wget-1.11.4-os2-20090315.zip -O dl.zip +unzip -j dl.zip wget/bin/wget.exe +del dl.zip + +wget ftp://ftp.os4.su/moveton/p7zip-9.04-bin-os2.zip -O dl.zip +unzip -j dl.zip bin/7za.exe dll/ilibca.dll +del dl.zip + +cd .. + +:opengfx + +if exist opengfx goto opensfx + +mkdir opengfx +sed s/OPENGFX_VERSION/%OPENGFX_VERSION%/ < download_opengfx.cmd > opengfx\download_opengfx.cmd +copy remove_opengfx.cmd opengfx + +:opensfx +if exist opensfx goto nosound + +mkdir opensfx +sed s/OPENSFX_VERSION/%OPENSFX_VERSION%/ < download_opensfx.cmd > opensfx\download_opensfx.cmd +copy remove_opensfx.cmd opensfx + +:nosound + +mkdir nosound +sed s/NOSOUND_VERSION/%NOSOUND_VERSION%/ < download_nosound.cmd > nosound\download_nosound.cmd +copy remove_nosound.cmd nosound + +:end + +if exist openttd-%OPENTTD_VERSION%-os2.exe del openttd-%OPENTTD_VERSION%-os2.exe +wic -a openttd-%OPENTTD_VERSION%-os2.exe 1 -c../../../bundle -r * 2 -ctools -r * 3 -copengfx -r * 4 -copensfx -r * 5 -cnosound -r * -U -s openttd.wis diff --git a/os/os2/installer/openttd.wis b/os/os2/installer/openttd.wis new file mode 100644 index 0000000..e580e56 --- /dev/null +++ b/os/os2/installer/openttd.wis @@ -0,0 +1,106 @@ + + +OpenTTD + + + +OpenTTD is an open source transport simulation game + +Tools required for downloading the OpenGFX/SFX packs + +Downloads the OpenGFX graphics pack for OpenTTD + +Downloads the OpenSFX sound effects pack for OpenTTD + +Downloads the NoSound pack for OpenTTD, to disable sound effects + + + + + + +~Next +README.TXT +Welcome to the OpenTTD installer. This program will install OpenTTD 1.0 on your system. Before we begin the installation process, please take a moment to read the following document. + +Select "Next" to continue, or "Cancel" to abort installation. + + + + +~Next +COPYING +OpenTTD is licenced under the GNU General Public License. The text of the licence is below. + +Select "Next" if you agree to this licence. +Select "Cancel" to abort installation. + + + + +~Next +On this page, you may choose which components to install. If you don't own Transport Tycoon Deluxe, you will need to download OpenGFX (3MiB) and OpenSFX (10MiB). + + + + + +I~nstall + +Press "Install" to begin installing OpenTTD. + + + diff --git a/os/os2/installer/remove_nosound.cmd b/os/os2/installer/remove_nosound.cmd new file mode 100644 index 0000000..21c11e8 --- /dev/null +++ b/os/os2/installer/remove_nosound.cmd @@ -0,0 +1,15 @@ +@echo off +if "%1" == "" goto err + +echo Removing NoSound... + +del %1\baseset\nosound\*.* /n +rmdir %1\baseset\nosound + +echo NoSound has been removed. +goto end + +:err +echo This batch file is only intended for use by the OpenTTD installer. + +:end diff --git a/os/os2/installer/remove_opengfx.cmd b/os/os2/installer/remove_opengfx.cmd new file mode 100644 index 0000000..71465d1 --- /dev/null +++ b/os/os2/installer/remove_opengfx.cmd @@ -0,0 +1,15 @@ +@echo off +if "%1" == "" goto err + +echo Removing OpenGFX... + +del %1\baseset\opengfx\*.* /n +rmdir %1\baseset\opengfx + +echo OpenGFX has been removed. +goto end + +:err +echo This batch file is only intended for use by the OpenTTD installer. + +:end diff --git a/os/os2/installer/remove_opensfx.cmd b/os/os2/installer/remove_opensfx.cmd new file mode 100644 index 0000000..361a870 --- /dev/null +++ b/os/os2/installer/remove_opensfx.cmd @@ -0,0 +1,15 @@ +@echo off +if "%1" == "" goto err + +echo Removing OpenSFX... + +del %1\baseset\opensfx\*.* /n +rmdir %1\baseset\opensfx + +echo OpenSFX has been removed. +goto end + +:err +echo This batch file is only intended for use by the OpenTTD installer. + +:end diff --git a/os/os2/openttd.wpj b/os/os2/openttd.wpj new file mode 100644 index 0000000..61b2caa --- /dev/null +++ b/os/os2/openttd.wpj @@ -0,0 +1,64 @@ +40 +projectIdent +0 +VpeMain +1 +WRect +0 +0 +10304 +10020 +2 +MProject +3 +MCommand +15 +svn_version.cmd +4 +MCommand +0 +2 +5 +WFileName +17 +..\..\openttd.tgt +6 +WFileName +23 +..\..\strgen\strgen.tgt +7 +WVList +2 +8 +VComponent +9 +WRect +0 +0 +5696 +4240 +0 +0 +10 +WFileName +17 +..\..\openttd.tgt +0 +0 +11 +VComponent +12 +WRect +688 +680 +5696 +4240 +0 +0 +13 +WFileName +23 +..\..\strgen\strgen.tgt +0 +1 +8 diff --git a/os/os2/svn_version.cmd b/os/os2/svn_version.cmd new file mode 100644 index 0000000..cc8836f --- /dev/null +++ b/os/os2/svn_version.cmd @@ -0,0 +1,30 @@ +@echo off +echo Running SVN version detection script... +rem +rem Requires subversion (`svnversion') to be installed +rem +cd ..\.. +if not "%RELEASE%"=="" goto forcerelease +if not exist .svn goto nosvn +svnversion -n . > os\os2\svnver.tmp +if not "%ERRORLEVEL%"=="0" goto nosvn + +copy os\os2\svnver1.c+os\os2\svnver.tmp+os\os2\svnver2.c rev.c /a /y > nul 2> nul +goto end + +:forcerelease +echo Forcing release string "%RELEASE%"... +echo const char _openttd_revision[] = "%RELEASE%"; > rev.c +echo const int _revision_number = 0; >> rev.c +goto end + +:nosvn +echo Error executing `svnversion' or no SVN data detected +echo const char _openttd_revision[] = "norev000"; > rev.c +echo const int _revision_number = 0; >> rev.c +goto end + +:end +cd os\os2 +del svnver.tmp > nul 2> nul +rem end diff --git a/os/os2/svnver1.c b/os/os2/svnver1.c new file mode 100644 index 0000000..56d3572 --- /dev/null +++ b/os/os2/svnver1.c @@ -0,0 +1,3 @@ +/* rev.c part #1 for OS/2 - ensure no newline at end of file! */ + +const char _openttd_revision[] = "r \ No newline at end of file diff --git a/os/os2/svnver2.c b/os/os2/svnver2.c new file mode 100644 index 0000000..02d8760 --- /dev/null +++ b/os/os2/svnver2.c @@ -0,0 +1,4 @@ +"; +const int _revision_number = 0; + +/* rev.c part 2 for OS/2 - ensure no newline at start of file! */ \ No newline at end of file diff --git a/os/rpm/openttd-rpmlintrc b/os/rpm/openttd-rpmlintrc new file mode 100644 index 0000000..f8d5fb9 --- /dev/null +++ b/os/rpm/openttd-rpmlintrc @@ -0,0 +1,6 @@ +# the man page is in the subpackage data +addFilter("openttd.*: W: no-manual-page-for-binary openttd") +# no other package depends on this package, so this should not matter +addFilter("openttd.*: W: file-contains-date-and-time /usr/bin/openttd") +addFilter("openttd.*: W: file-contains-current-date /usr/bin/openttd") + diff --git a/os/rpm/openttd.changes b/os/rpm/openttd.changes new file mode 100644 index 0000000..b0a64df --- /dev/null +++ b/os/rpm/openttd.changes @@ -0,0 +1,100 @@ +------------------------------------------------------------------- +Sun Mar 6 09:36:55 UTC 2011 - ammler@openttdcoop.org + +- upstream update 1.1.0-RC2 + * Feature: XZ/LZMA2 savegame support. New default reduces + savegame size by 10 to 30% with slightly more CPU usage. + (requires xz-devel) + * Feature: Remote administration + * Feature: a lot improvements with GUI + * Feature: Customizable hotkeys + * Sources for openttd.grf are pngs (requires grfcodec >= 5.1) + +------------------------------------------------------------------- +Sun Nov 21 11:11:38 UTC 2010 - ammler@openttdcoop.org + +- upstream update 1.0.5 + * Fix: Reading (very) recently freed memory [CVE-2010-4168] + +------------------------------------------------------------------- +Sun Oct 31 17:53:41 UTC 2010 - ammler@openttdcoop.org + +- upstream update 1.0.4 + * build openttd.grf from source + +------------------------------------------------------------------- +Tue Aug 10 20:16:03 UTC 2010 - ammler@openttdcoop.org + +- upstream update 1.0.3 + +------------------------------------------------------------------- +Wed Jun 23 11:42:59 UTC 2010 - Marcel Gmür + +- upstream update 1.0.2 + * Feature: Translated desktop shortcut comments (r19884) + * many minor Bugfixes + +------------------------------------------------------------------- +Sat May 1 15:59:32 UTC 2010 - Marcel Gmür + +- upstream update 1.0.1 + * Fix: Leaking a file descriptor + * Fix a lot small bugs, like minor desync issues on Mulitplayer +- no strip on make + +------------------------------------------------------------------- +Thu Apr 1 08:53:54 UTC 2010 - Marcel Gmür + +- upstream update 1.0.0 (finally!) + * completely independend game but still working also + with ttd original gaphics, sounds and music +- Add: Recommends openmsx +- requires lzo2 + +------------------------------------------------------------------- +Fri Dec 18 2009 Marcel Gmür - 0.7.4 + +- support for differen branches +- easy support for dedicated branch +- let openttd build system make the dektop file +- split the package to data and gui +- disable requires + +------------------------------------------------------------------- +Thu Oct 01 2009 Marcel Gmür - 0.7.3 + +- disable libicu for RHEL4 + +------------------------------------------------------------------- +Sat Sep 26 2009 Marcel Gmür - 0.7.2 + +- no subfolder games for datadir +- cleanup: no post and postun anymore +- Recommends: opengfx (for suse and mandriva) +- add SUSE support + +------------------------------------------------------------------- +Mon Oct 20 2008 Benedikt Brüggemeier + +- Added libicu dependency + +------------------------------------------------------------------- +Thu Sep 23 2008 Benedikt Brüggemeier + +- Merged both versions of the spec file + +------------------------------------------------------------------- +Fri Aug 29 2008 Jonathan Coome + +- Rewrite spec file from scratch. + +------------------------------------------------------------------- +Sat Aug 02 2008 Benedikt Brüggemeier + +- Updated spec file + +------------------------------------------------------------------- +Thu Mar 27 2008 Denis Burlaka + +- Universal spec file + diff --git a/os/rpm/openttd.spec b/os/rpm/openttd.spec new file mode 100644 index 0000000..cd19fd9 --- /dev/null +++ b/os/rpm/openttd.spec @@ -0,0 +1,272 @@ +# +# spec file for package openttd +# +# Copyright (c) 2012 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2007-2012 The OpenTTD developers +# +# All modifications and additions to the file contributed by third parties +# remain the property of their copyright owners, unless otherwise agreed +# upon. The license for this file, and modifications and additions to the +# file, is the same license as for the pristine package itself (unless the +# license for the pristine package is not an Open Source License, in which +# case the license is the MIT License). An "Open Source License" is a +# license that conforms to the Open Source Definition (Version 1.9) +# published by the Open Source Initiative. + +# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# + +Name: openttd +Version: 1.5.beta1 +Release: 0 +%define srcver 1.5.0-beta1 +Summary: An open source reimplementation of Chris Sawyer's Transport Tycoon Deluxe +License: GPL-2.0 +Group: Amusements/Games/Strategy/Other +Url: http://www.openttd.org + +Source: http://binaries.openttd.org/releases/%{srcver}/%{name}-%{srcver}-source.tar.gz + +%if 0%{?suse_version} || 0%{?mdkversion} +Recommends: %{name}-gui +%endif + +BuildRequires: gcc-c++ +BuildRequires: libpng-devel +BuildRequires: zlib-devel + +%if 0%{?suse_version} || 0%{?mdkversion} +BuildRequires: update-alternatives +Requires: update-alternatives +%else +BuildRequires: chkconfig +Requires: chkconfig +%endif + +%if 0%{?mdkversion} +BuildRequires: liblzma-devel +BuildRequires: liblzo-devel +%else +BuildRequires: lzo-devel +BuildRequires: xz-devel +%endif + +# OBS workaround: needed by libdrm +%if 0%{?rhel_version} >= 600 || 0%{?centos_version} >= 600 +BuildRequires: kernel +%endif + +# for lzma detection +%if 0%{?suse_version} +BuildRequires: pkg-config +%endif + +# bulding openttd.grf is not required as it is a) part of source and +# b) required only, if you want to use the original set +%if 0%{?with_grfcodec} +BuildRequires: grfcodec +%endif +# Recommends would fit better but not well supported... +Requires: openttd-opengfx >= 0.4.2 + +Obsoletes: %{name}-data < %{version} +Provides: %{name}-data = %{version} + +BuildRoot: %{_tmppath}/%{name}-%{version}-build + +%description +OpenTTD is a reimplementation of the Microprose game "Transport Tycoon Deluxe" +with lots of new features and enhancements. To play the game you need either +the original data from the game or install the recommend subackages OpenGFX for +free graphics, OpenSFX for free sounds and OpenMSX for free music. + +OpenTTD is licensed under the GNU General Public License version 2.0. For more +information, see the file 'COPYING' included with every release and source +download of the game. + +%package gui +Summary: OpenTTD GUI/Client (requires SDL) +Group: Amusements/Games/Strategy/Other + +Requires: %{name} +Conflicts: %{name}-dedicated + +BuildRequires: SDL-devel +BuildRequires: fontconfig-devel + +%if 0%{?rhel_version} != 600 +BuildRequires: libicu-devel +%endif +%if 0%{?rhel_version} || 0%{?fedora} +BuildRequires: freetype-devel +%endif +%if 0%{?suse_version} || 0%{?mdkversion} +BuildRequires: freetype2-devel +%endif +%if 0%{?suse_version} +BuildRequires: update-desktop-files +%else +BuildRequires: desktop-file-utils +Requires: hicolor-icon-theme +%endif + +%if 0%{?suse_version} || 0%{?mdkversion} +Recommends: openttd-openmsx +Recommends: openttd-opensfx +%endif + +%description gui +OpenTTD is a reimplementation of the Microprose game "Transport Tycoon Deluxe" +with lots of new features and enhancements. To play the game you need either +the original data from the game or install the recommend subackages OpenGFX for +free graphics, OpenSFX for free sounds and OpenMSX for free music. + +This subpackage provides the binary which needs SDL. + +%package dedicated +Summary: OpenTTD Dedicated Server binary (without SDL) +Group: Amusements/Games/Strategy/Other + +Requires: %{name} +Conflicts: %{name}-gui + +%description dedicated +OpenTTD is a reimplementation of the Microprose game "Transport Tycoon Deluxe" +with lots of new features and enhancements. To play the game you need either +the original data from the game or the required package OpenGFX and OpenSFX. + +This subpackage provides the binary without dependency of SDL. + +%prep +%setup -qn openttd%{?branch:-%{branch}}-%{srcver} + +# we build the grfs from sources but validate the result with the existing data +%if 0%{?with_grfcodec} +md5sum bin/data/* > validate.data +%endif + +%build +# first, we build the dedicated binary and copy it to dedicated/ +./configure \ + --prefix-dir="%{_prefix}" \ + --binary-dir="bin" \ + --data-dir="share/%{name}" \ + --enable-dedicated +make %{?_smp_mflags} BUNDLE_DIR="dedicated" bundle + +# then, we build the common gui version which we install the usual way +./configure \ + --prefix-dir="%{_prefix}" \ + --binary-name="%{name}" \ + --binary-dir="bin" \ + --data-dir="share/%{name}" \ + --doc-dir="share/doc/%{name}" \ + --menu-name="OpenTTD%{?branch: %{branch}}" \ + --menu-group="Game;StrategyGame;" + +make %{?_smp_mflags} + +%install +# install the dedicated binary +install -D -m0755 dedicated/openttd %{buildroot}%{_bindir}/%{name}-dedicated +# install the gui binary and rename to openttd-gui +make install INSTALL_DIR=%{buildroot} +mv %{buildroot}%{_bindir}/%{name} %{buildroot}%{_bindir}/%{name}-gui +# we need a dummy target for /etc/alternatives/openttd +mkdir -p %{buildroot}%{_sysconfdir}/alternatives +touch %{buildroot}%{_sysconfdir}/alternatives/%{name} +ln -s -f /etc/alternatives/%{name} %{buildroot}%{_bindir}/%{name} + +%if 0%{?suse_version} +%suse_update_desktop_file -r %{name} Game StrategyGame +%else +%if 0%{?fedora} || 0%{?rhel_version} >= 600 || 0%{?centos_version} >= 600 +desktop-file-install --dir=%{buildroot}%{_datadir}/applications \ + --add-category=StrategyGame \ + media/openttd.desktop +%endif +%endif + +%if 0%{?with_grfcodec} +%check +md5sum -c validate.data +%endif + +%post gui +/usr/sbin/update-alternatives --install %{_bindir}/%{name} %{name} %{_bindir}/%{name}-gui 10 +touch --no-create %{_datadir}/icons/hicolor &>/dev/null || : + +%post dedicated +/usr/sbin/update-alternatives --install %{_bindir}/%{name} %{name} %{_bindir}/%{name}-dedicated 0 + +%preun gui +if [ "$1" = 0 ] ; then + /usr/sbin/update-alternatives --remove %{name} %{_bindir}/%{name}-gui +fi + +%preun dedicated +if [ "$1" = 0 ] ; then + /usr/sbin/update-alternatives --remove %{name} %{_bindir}/%{name}-dedicated +fi + +%postun gui +if [ "$1" -eq 0 ] ; then + touch --no-create %{_datadir}/icons/hicolor &>/dev/null + gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || : +fi + +%posttrans gui +gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || : + +# we need a file in the main package so it will be made +%files +%defattr(-, root, root) +%dir %{_datadir}/doc/%{name} +%dir %{_datadir}/%{name} +%dir %{_datadir}/%{name}/lang +%dir %{_datadir}/%{name}/baseset +%dir %{_datadir}/%{name}/scripts +%dir %{_datadir}/%{name}/ai +%dir %{_datadir}/%{name}/game +%{_datadir}/doc/%{name}/* +%{_datadir}/%{name}/lang/* +%{_datadir}/%{name}/baseset/* +%{_datadir}/%{name}/scripts/* +%{_datadir}/%{name}/ai/* +%{_datadir}/%{name}/game/* +%doc %{_mandir}/man6/%{name}.6.* + +%files gui +%defattr(-, root, root) +%ghost %{_sysconfdir}/alternatives/%{name} +%ghost %{_bindir}/%{name} +%{_bindir}/%{name}-gui +%dir %{_datadir}/icons/hicolor +%dir %{_datadir}/icons/hicolor/16x16 +%dir %{_datadir}/icons/hicolor/16x16/apps +%dir %{_datadir}/icons/hicolor/32x32 +%dir %{_datadir}/icons/hicolor/32x32/apps +%dir %{_datadir}/icons/hicolor/48x48 +%dir %{_datadir}/icons/hicolor/48x48/apps +%dir %{_datadir}/icons/hicolor/64x64 +%dir %{_datadir}/icons/hicolor/64x64/apps +%dir %{_datadir}/icons/hicolor/128x128 +%dir %{_datadir}/icons/hicolor/128x128/apps +%dir %{_datadir}/icons/hicolor/256x256 +%dir %{_datadir}/icons/hicolor/256x256/apps +%{_datadir}/applications/%{name}.desktop +%{_datadir}/icons/hicolor/16x16/apps/%{name}.png +%{_datadir}/icons/hicolor/32x32/apps/%{name}.png +%{_datadir}/icons/hicolor/48x48/apps/%{name}.png +%{_datadir}/icons/hicolor/64x64/apps/%{name}.png +%{_datadir}/icons/hicolor/128x128/apps/%{name}.png +%{_datadir}/icons/hicolor/256x256/apps/%{name}.png +%{_datadir}/pixmaps/%{name}.32.xpm + +%files dedicated +%defattr(-, root, root) +%ghost %{_bindir}/%{name} +%ghost %{_sysconfdir}/alternatives/%{name} +%{_bindir}/%{name}-dedicated + +%changelog diff --git a/os/windows/installer/build_installers.bat b/os/windows/installer/build_installers.bat new file mode 100644 index 0000000..73a2898 --- /dev/null +++ b/os/windows/installer/build_installers.bat @@ -0,0 +1,4 @@ +@echo off +"c:\Program Files\NSIS\makensis.exe" /DVERSION_INCLUDE=version_win9x.txt install.nsi > win9x.log +"c:\Program Files\NSIS\makensis.exe" /DVERSION_INCLUDE=version_win32.txt install.nsi > win32.log +"c:\Program Files\NSIS\makensis.exe" /DVERSION_INCLUDE=version_win64.txt install.nsi > win64.log diff --git a/os/windows/installer/cdfinder.ini b/os/windows/installer/cdfinder.ini new file mode 100644 index 0000000..45f9602 --- /dev/null +++ b/os/windows/installer/cdfinder.ini @@ -0,0 +1,26 @@ +; Ini file generated by the HM NIS Edit IO designer. +[Settings] +NumFields=3 + +[Field 1] +Type=Groupbox +Text=Transport Tycoon Deluxe Installation location +Left=6 +Right=294 +Top=68 +Bottom=100 + +[Field 2] +Type=DirRequest +Left=10 +Right=290 +Top=80 +Bottom=92 + +[Field 3] +Type=Label +Left=17 +Right=282 +Top=6 +Bottom=64 + diff --git a/os/windows/installer/install.nsi b/os/windows/installer/install.nsi new file mode 100644 index 0000000..2abec4a --- /dev/null +++ b/os/windows/installer/install.nsi @@ -0,0 +1,737 @@ +# Version numbers to update +!define APPV_MAJOR 1 +!define APPV_MINOR 5 +!define APPV_MAINT 3 +!define APPV_BUILD 1 +!define APPV_EXTRA "" + +!define APPNAME "OpenTTD" ; Define application name +!define APPVERSION "${APPV_MAJOR}.${APPV_MINOR}.${APPV_MAINT}${APPV_EXTRA}" ; Define application version +!define APPVERSIONINTERNAL "${APPV_MAJOR}.${APPV_MINOR}.${APPV_MAINT}.${APPV_BUILD}" ; Define application version in X.X.X.X +!define INSTALLERVERSION ${APPV_MAJOR}${APPV_MINOR}${APPV_MAINT}${APPV_BUILD} +!include ${VERSION_INCLUDE} + +!define APPURLLINK "http://www.openttd.org" +!define APPNAMEANDVERSION "${APPNAME} ${APPVERSION}" + +!define OPENGFX_BASE_VERSION "1.2.0" +!define OPENSFX_BASE_VERSION "0.8.0" +!define OPENMSX_BASE_VERSION "1.0.0" + +!define MUI_ICON "..\..\..\media\openttd.ico" +!define MUI_UNICON "..\..\..\media\openttd.ico" +!define MUI_WELCOMEFINISHPAGE_BITMAP "welcome.bmp" +!define MUI_HEADERIMAGE +!define MUI_HEADERIMAGE_BITMAP "top.bmp" + +BrandingText "OpenTTD Installer" +SetCompressor LZMA + +; Version Info +Var AddWinPrePopulate +VIProductVersion "${APPVERSIONINTERNAL}" +VIAddVersionKey "ProductName" "OpenTTD ${APPBITS}-bit Installer for Windows ${EXTRA_VERSION}" +VIAddVersionKey "Comments" "Installs ${APPNAMEANDVERSION}" +VIAddVersionKey "CompanyName" "OpenTTD Developers" +VIAddVersionKey "FileDescription" "Installs ${APPNAMEANDVERSION}" +VIAddVersionKey "ProductVersion" "${APPVERSION}" +VIAddVersionKey "InternalName" "InstOpenTTD-${APPARCH}" +VIAddVersionKey "FileVersion" "${APPVERSION}-${APPARCH}" +VIAddVersionKey "LegalCopyright" " " +; Main Install settings +Name "${APPNAMEANDVERSION} ${APPBITS}-bit for Windows ${EXTRA_VERSION}" + +; NOTE: Keep trailing backslash! +InstallDirRegKey HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "Install Folder" +OutFile "openttd-${APPVERSION}-${APPARCH}.exe" +CRCCheck force + +ShowInstDetails show +ShowUninstDetails show + +RequestExecutionLevel admin + +Var SHORTCUTS +Var CDDRIVE + +; Modern interface settings +!include "MUI2.nsh" +!include "InstallOptions.nsh" +!include "WinVer.nsh" + +!define MUI_ABORTWARNING +!define MUI_WELCOMEPAGE_TITLE_3LINES +!insertmacro MUI_PAGE_WELCOME +!insertmacro MUI_PAGE_LICENSE "..\..\..\COPYING" + +!define MUI_COMPONENTSPAGE_SMALLDESC +!insertmacro MUI_PAGE_COMPONENTS + +;--------------------------------- +; Custom page for finding TTDLX CD +Page custom SelectCDEnter SelectCDExit ": TTD folder" + +!insertmacro MUI_PAGE_DIRECTORY + +;Start Menu Folder Page Configuration +!define MUI_STARTMENUPAGE_DEFAULTFOLDER $SHORTCUTS +!define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKEY_LOCAL_MACHINE" +!define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" +!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Shortcut Folder" + +!insertmacro MUI_PAGE_STARTMENU "OpenTTD" $SHORTCUTS + +!insertmacro MUI_PAGE_INSTFILES + +!define MUI_FINISHPAGE_TITLE_3LINES +!define MUI_FINISHPAGE_RUN_TEXT "Run ${APPNAMEANDVERSION} now!" +!define MUI_FINISHPAGE_RUN "$INSTDIR\openttd.exe" +!define MUI_FINISHPAGE_LINK "Visit the OpenTTD site for more information" +!define MUI_FINISHPAGE_LINK_LOCATION "${APPURLLINK}" +!define MUI_FINISHPAGE_NOREBOOTSUPPORT +!define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\readme.txt" +!define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED +!define MUI_WELCOMEFINISHPAGE_CUSTOMFUNCTION_INIT DisableBack + +!insertmacro MUI_PAGE_FINISH +!define MUI_PAGE_HEADER_TEXT "Uninstall ${APPNAMEANDVERSION}" +!insertmacro MUI_UNPAGE_CONFIRM +!insertmacro MUI_UNPAGE_INSTFILES + +; Set languages (first is default language) +!insertmacro MUI_LANGUAGE "English" +!insertmacro MUI_RESERVEFILE_LANGDLL + +;-------------------------------------------------------------- +; (Core) OpenTTD install section. Copies all internal game data +Section "!OpenTTD" Section1 + ; Make sure to be upgraded OpenTTD is not running + Call CheckOpenTTDRunning + + ; Overwrite files by default, but don't complain on failure + SetOverwrite try + + SetShellVarContext all + + ; Define root variable relative to installer + !define PATH_ROOT "..\..\..\" + + ; Copy language files + SetOutPath "$INSTDIR\lang\" + File ${PATH_ROOT}bin\lang\english.lng + + ; Copy AI files + SetOutPath "$INSTDIR\ai\" + File ${PATH_ROOT}bin\ai\compat_*.nut + + ; Copy Game Script files + SetOutPath "$INSTDIR\game\" + File ${PATH_ROOT}bin\game\compat_*.nut + + ; Copy data files + SetOutPath "$INSTDIR\baseset\" + File ${PATH_ROOT}bin\baseset\*.grf + File ${PATH_ROOT}bin\baseset\*.obg + File ${PATH_ROOT}bin\baseset\*.obm + File ${PATH_ROOT}bin\baseset\*.obs + File ${PATH_ROOT}bin\baseset\opntitle.dat + + ; Copy the scripts + SetOutPath "$INSTDIR\scripts\" + File ${PATH_ROOT}bin\scripts\*.* + Push "$INSTDIR\scripts\readme.txt" + Call unix2dos + + ; Copy some documention files + SetOutPath "$INSTDIR\docs\" + File ${PATH_ROOT}docs\multiplayer.txt + Push "$INSTDIR\docs\multiplayer.txt" + Call unix2dos + + ; Copy the rest of the stuff + SetOutPath "$INSTDIR\" + + ; Copy text files + File ${PATH_ROOT}changelog.txt + Push "$INSTDIR\changelog.txt" + Call unix2dos + File ${PATH_ROOT}COPYING + Push "$INSTDIR\COPYING" + Call unix2dos + File ${PATH_ROOT}readme.txt + Push "$INSTDIR\readme.txt" + Call unix2dos + File ${PATH_ROOT}known-bugs.txt + Push "$INSTDIR\known-bugs.txt" + Call unix2dos + + ; Copy executable + File /oname=openttd.exe ${BINARY_DIR}\openttd.exe + + + ; Delete old files from the main dir. they are now placed in baseset/ and lang/ + Delete "$INSTDIR\*.lng" + Delete "$INSTDIR\*.grf" + Delete "$INSTDIR\sample.cat" + Delete "$INSTDIR\ttd.exe" + Delete "$INSTDIR\data\opntitle.dat" + Delete "$INSTDIR\data\2ccmap.grf" + Delete "$INSTDIR\data\airports.grf" + Delete "$INSTDIR\data\autorail.grf" + Delete "$INSTDIR\data\canalsw.grf" + Delete "$INSTDIR\data\dosdummy.grf" + Delete "$INSTDIR\data\elrailsw.grf" + Delete "$INSTDIR\data\nsignalsw.grf" + Delete "$INSTDIR\data\openttd.grf" + Delete "$INSTDIR\data\roadstops.grf" + Delete "$INSTDIR\data\trkfoundw.grf" + Delete "$INSTDIR\data\openttdd.grf" + Delete "$INSTDIR\data\openttdw.grf" + Delete "$INSTDIR\data\orig_win.obg" + Delete "$INSTDIR\data\orig_dos.obg" + Delete "$INSTDIR\data\orig_dos_de.obg" + Delete "$INSTDIR\data\orig_win.obs" + Delete "$INSTDIR\data\orig_dos.obs" + Delete "$INSTDIR\data\no_sound.obs" + + ; Create the Registry Entries + WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "Comments" "Visit ${APPURLLINK}" + WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "DisplayIcon" "$INSTDIR\openttd.exe,0" + WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "DisplayName" "OpenTTD ${APPVERSION}" + WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "DisplayVersion" "${APPVERSION}" + WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "HelpLink" "${APPURLLINK}" + WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "Install Folder" "$INSTDIR" + WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "Publisher" "OpenTTD" + WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "Shortcut Folder" "$SHORTCUTS" + WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "UninstallString" "$INSTDIR\uninstall.exe" + WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "URLInfoAbout" "${APPURLLINK}" + ; This key sets the Version DWORD that new installers will check against + WriteRegDWORD HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "Version" ${INSTALLERVERSION} + + !insertmacro MUI_STARTMENU_WRITE_BEGIN "OpenTTD" + CreateShortCut "$DESKTOP\OpenTTD.lnk" "$INSTDIR\openttd.exe" + CreateDirectory "$SMPROGRAMS\$SHORTCUTS" + CreateShortCut "$SMPROGRAMS\$SHORTCUTS\OpenTTD.lnk" "$INSTDIR\openttd.exe" + CreateShortCut "$SMPROGRAMS\$SHORTCUTS\Uninstall.lnk" "$INSTDIR\uninstall.exe" + CreateShortCut "$SMPROGRAMS\$SHORTCUTS\Readme.lnk" "$INSTDIR\Readme.txt" + CreateShortCut "$SMPROGRAMS\$SHORTCUTS\Changelog.lnk" "$INSTDIR\Changelog.txt" + CreateShortCut "$SMPROGRAMS\$SHORTCUTS\Known-bugs.lnk" "$INSTDIR\known-bugs.txt" + CreateDirectory "$SMPROGRAMS\$SHORTCUTS\Docs" + CreateShortCut "$SMPROGRAMS\$SHORTCUTS\Docs\Multiplayer.lnk" "$INSTDIR\docs\multiplayer.txt" + CreateDirectory "$SMPROGRAMS\$SHORTCUTS\Scripts" + CreateShortCut "$SMPROGRAMS\$SHORTCUTS\Scripts\Readme.lnk" "$INSTDIR\scripts\readme.txt" + !insertmacro MUI_STARTMENU_WRITE_END +SectionEnd + +;-------------------------------------------------------------- +; OpenTTD translation install section. Copies only translations +Section "OpenTTD translations" Section6 + ; Overwrite files by default, but don't complain on failure + SetOverwrite try + + ; Copy language files + SetOutPath "$INSTDIR\lang\" + File ${PATH_ROOT}bin\lang\*.lng +SectionEnd + +;---------------------------------------------------------------------------------- +; OpenGFX files install section. Downloads OpenGFX and installs it +Section "Download OpenGFX (free graphics set)" Section3 + SetOverwrite try + + NSISdl::download "http://binaries.openttd.org/installer/opengfx-${OPENGFX_BASE_VERSION}.7z" "$INSTDIR\baseset\opengfx.7z" + Pop $R0 ;Get the return value + StrCmp $R0 "success" +3 + MessageBox MB_OK "Downloading of OpenGFX failed" + Goto Done + + ; Let's extract the files + SetOutPath "$INSTDIR\baseset\" + NSIS7z::Extract "$INSTDIR\baseset\opengfx.7z" + + Delete "$INSTDIR\baseset\opengfx.7z" + SetOutPath "$INSTDIR\" +Done: + +SectionEnd + +;---------------------------------------------------------------------------------- +; OpenSFX files install section. Downloads OpenSFX and installs it +Section "Download OpenSFX (free sound set)" Section4 + SetOverwrite try + + NSISdl::download "http://binaries.openttd.org/installer/opensfx-${OPENSFX_BASE_VERSION}.7z" "$INSTDIR\baseset\opensfx.7z" + Pop $R0 ;Get the return value + StrCmp $R0 "success" +3 + MessageBox MB_OK "Downloading of OpenSFX failed" + Goto Done + + ; Let's extract the files + SetOutPath "$INSTDIR\baseset\" + NSIS7z::Extract "$INSTDIR\baseset\opensfx.7z" + + Delete "$INSTDIR\baseset\opensfx.7z" + SetOutPath "$INSTDIR\" +Done: + +SectionEnd + +;---------------------------------------------------------------------------------- +; OpenMSX files install section. Downloads OpenMSX and installs it +Section "Download OpenMSX (free music set)" Section5 + SetOverwrite try + + NSISdl::download "http://binaries.openttd.org/installer/openmsx-${OPENMSX_BASE_VERSION}.7z" "$INSTDIR\baseset\openmsx.7z" + Pop $R0 ;Get the return value + StrCmp $R0 "success" +3 + MessageBox MB_OK "Downloading of OpenMSX failed" + Goto Done + + ; Let's extract the files + SetOutPath "$INSTDIR\baseset\" + NSIS7z::Extract "$INSTDIR\baseset\openmsx.7z" + + Delete "$INSTDIR\baseset\openmsx.7z" + SetOutPath "$INSTDIR\" +Done: + +SectionEnd + +;---------------------------------------------------------------------------------- +; TTDLX files install section. Copies all needed TTDLX files from CD or install dir +Section /o "Copy data from Transport Tycoon Deluxe CD-ROM" Section2 + SetOverwrite try + ; Let's copy the files with size approximation + SetOutPath "$INSTDIR\baseset" + CopyFiles "$CDDRIVE\gm\*.gm" "$INSTDIR\baseset\" 1028 + CopyFiles "$CDDRIVE\sample.cat" "$INSTDIR\baseset\sample.cat" 1566 + ; Copy Windows files + CopyFiles "$CDDRIVE\trg1r.grf" "$INSTDIR\baseset\trg1r.grf" 2365 + CopyFiles "$CDDRIVE\trgcr.grf" "$INSTDIR\baseset\trgcr.grf" 260 + CopyFiles "$CDDRIVE\trghr.grf" "$INSTDIR\baseset\trghr.grf" 400 + CopyFiles "$CDDRIVE\trgir.grf" "$INSTDIR\baseset\trgir.grf" 334 + CopyFiles "$CDDRIVE\trgtr.grf" "$INSTDIR\baseset\trgtr.grf" 546 + ; Copy DOS files + CopyFiles "$CDDRIVE\trg1.grf" "$INSTDIR\baseset\trg1.grf" 2365 + CopyFiles "$CDDRIVE\trgc.grf" "$INSTDIR\baseset\trgc.grf" 260 + CopyFiles "$CDDRIVE\trgh.grf" "$INSTDIR\baseset\trgh.grf" 400 + CopyFiles "$CDDRIVE\trgi.grf" "$INSTDIR\baseset\trgi.grf" 334 + CopyFiles "$CDDRIVE\trgt.grf" "$INSTDIR\baseset\trgt.grf" 546 + SetOutPath "$INSTDIR\" +SectionEnd + +;------------------------------------------- +; Install the uninstaller (option is hidden) +Section -FinishSection + WriteUninstaller "$INSTDIR\uninstall.exe" +SectionEnd + +; Modern install component descriptions +!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN + !insertmacro MUI_DESCRIPTION_TEXT ${Section1} "Minimal OpenTTD installation in English. You need at least one of the game graphics and sound sets installed." + !insertmacro MUI_DESCRIPTION_TEXT ${Section6} "Translations of OpenTTD." + !insertmacro MUI_DESCRIPTION_TEXT ${Section3} "Download the free OpenGFX game graphics set. This download is about 3 MiB." + !insertmacro MUI_DESCRIPTION_TEXT ${Section4} "Download the free OpenSFX game sound set. This download is about 10 MiB." + !insertmacro MUI_DESCRIPTION_TEXT ${Section5} "Download the free OpenMSX game music set. This download is about 200 KiB." + !insertmacro MUI_DESCRIPTION_TEXT ${Section2} "Copies the game graphics, sounds and music from the Transport Tycoon Deluxe CD." +!insertmacro MUI_FUNCTION_DESCRIPTION_END + +;----------------------------------------------- +; Uninstall section, deletes all installed files +Section "Uninstall" + SetShellVarContext all + + IfFileExists "$INSTDIR\save" 0 NoRemoveSavedGames + MessageBox MB_YESNO|MB_ICONQUESTION \ + "Remove the save game folders located at $\"$INSTDIR\save$\"?$\n \ + If you choose Yes, your saved games will be deleted." \ + IDYES RemoveSavedGames IDNO NoRemoveSavedGames + RemoveSavedGames: + Delete "$INSTDIR\save\autosave\*" + RMDir "$INSTDIR\save\autosave" + Delete "$INSTDIR\save\*" + RMDir "$INSTDIR\save" + NoRemoveSavedGames: + + IfFileExists "$INSTDIR\scenario" 0 NoRemoveScen + MessageBox MB_YESNO|MB_ICONQUESTION \ + "Remove the scenario folders located at $\"$INSTDIR\scenario$\"?$\n \ + If you choose Yes, your scenarios will be deleted." \ + IDYES RemoveScen IDNO NoRemoveScen + RemoveScen: + Delete "$INSTDIR\scenario\heightmap*" + RMDir "$INSTDIR\scenario\heightmap" + Delete "$INSTDIR\scenario\*" + RMDir "$INSTDIR\scenario" + NoRemoveScen: + + ; Remove from registry... + !insertmacro MUI_STARTMENU_GETFOLDER "OpenTTD" $SHORTCUTS + ReadRegStr $SHORTCUTS HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "Shortcut Folder" + + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" + + ; Delete self + Delete "$INSTDIR\uninstall.exe" + + ; Delete Shortcuts + Delete "$DESKTOP\OpenTTD.lnk" + Delete "$SMPROGRAMS\$SHORTCUTS\OpenTTD.lnk" + Delete "$SMPROGRAMS\$SHORTCUTS\Uninstall.lnk" + Delete "$SMPROGRAMS\$SHORTCUTS\Readme.lnk" + Delete "$SMPROGRAMS\$SHORTCUTS\Changelog.lnk" + Delete "$SMPROGRAMS\$SHORTCUTS\Known-bugs.lnk" + Delete "$SMPROGRAMS\$SHORTCUTS\Docs\Multiplayer.lnk" + Delete "$SMPROGRAMS\$SHORTCUTS\Docs\32bpp.lnk" + Delete "$SMPROGRAMS\$SHORTCUTS\Scripts\Readme.lnk" + + ; Clean up OpenTTD dir + Delete "$INSTDIR\changelog.txt" + Delete "$INSTDIR\readme.txt" + Delete "$INSTDIR\known-bugs.txt" + Delete "$INSTDIR\openttd.exe" + Delete "$INSTDIR\COPYING" + Delete "$INSTDIR\INSTALL.LOG" + Delete "$INSTDIR\crash.log" + Delete "$INSTDIR\crash.dmp" + Delete "$INSTDIR\openttd.cfg" + Delete "$INSTDIR\hs.dat" + Delete "$INSTDIR\cached_sprites.*" + Delete "$INSTDIR\save\autosave\network*.tmp" ; temporary network file + + ; AI files + Delete "$INSTDIR\ai\compat_*.nut" + + ; Game Script files + Delete "$INSTDIR\game\compat_*.nut" + + ; Baseset files + Delete "$INSTDIR\baseset\opntitle.dat" + Delete "$INSTDIR\baseset\openttd.grf" + Delete "$INSTDIR\baseset\orig_win.obg" + Delete "$INSTDIR\baseset\orig_dos.obg" + Delete "$INSTDIR\baseset\orig_dos_de.obg" + Delete "$INSTDIR\baseset\orig_win.obs" + Delete "$INSTDIR\baseset\orig_dos.obs" + Delete "$INSTDIR\baseset\no_sound.obs" + Delete "$INSTDIR\baseset\sample.cat" + Delete "$INSTDIR\baseset\trg1r.grf" + Delete "$INSTDIR\baseset\trghr.grf" + Delete "$INSTDIR\baseset\trgtr.grf" + Delete "$INSTDIR\baseset\trgcr.grf" + Delete "$INSTDIR\baseset\trgir.grf" + Delete "$INSTDIR\baseset\trg1.grf" + Delete "$INSTDIR\baseset\trgh.grf" + Delete "$INSTDIR\baseset\trgt.grf" + Delete "$INSTDIR\baseset\trgc.grf" + Delete "$INSTDIR\baseset\trgi.grf" + Delete "$INSTDIR\baseset\*.gm" + + Delete "$INSTDIR\data\sample.cat" + Delete "$INSTDIR\data\trg1r.grf" + Delete "$INSTDIR\data\trghr.grf" + Delete "$INSTDIR\data\trgtr.grf" + Delete "$INSTDIR\data\trgcr.grf" + Delete "$INSTDIR\data\trgir.grf" + Delete "$INSTDIR\data\trg1.grf" + Delete "$INSTDIR\data\trgh.grf" + Delete "$INSTDIR\data\trgt.grf" + Delete "$INSTDIR\data\trgc.grf" + Delete "$INSTDIR\data\trgi.grf" + Delete "$INSTDIR\gm\*.gm" + + ; Downloaded OpenGFX/OpenSFX/OpenMSX + Delete "$INSTDIR\baseset\opengfx\*" + RMDir "$INSTDIR\baseset\opengfx" + Delete "$INSTDIR\baseset\opensfx\*" + RMDir "$INSTDIR\baseset\opensfx" + Delete "$INSTDIR\baseset\openmsx\*" + RMDir "$INSTDIR\baseset\openmsx" + + Delete "$INSTDIR\data\opengfx\*" + RMDir "$INSTDIR\data\opengfx" + Delete "$INSTDIR\data\opensfx\*" + RMDir "$INSTDIR\data\opensfx" + Delete "$INSTDIR\gm\openmsx\*" + RMDir "$INSTDIR\gm\openmsx" + + ; Language files + Delete "$INSTDIR\lang\*.lng" + + ; Scripts + Delete "$INSTDIR\scripts\*.*" + + ; Documentation + Delete "$INSTDIR\docs\*.*" + + ; Base sets for music + Delete "$INSTDIR\gm\orig_win.obm" + Delete "$INSTDIR\gm\no_music.obm" + Delete "$INSTDIR\baseset\orig_win.obm" + Delete "$INSTDIR\baseset\no_music.obm" + + ; Remove remaining directories + RMDir "$SMPROGRAMS\$SHORTCUTS\Extras\" + RMDir "$SMPROGRAMS\$SHORTCUTS\Scripts\" + RMDir "$SMPROGRAMS\$SHORTCUTS\Docs\" + RMDir "$SMPROGRAMS\$SHORTCUTS" + RMDir "$INSTDIR\ai" + RMDir "$INSTDIR\game" + RMDir "$INSTDIR\data" + RMDir "$INSTDIR\baseset" + RMDir "$INSTDIR\gm" + RMDir "$INSTDIR\lang" + RMDir "$INSTDIR\scripts" + RMDir "$INSTDIR\docs" + RMDir "$INSTDIR" + +SectionEnd + +;------------------------------------------------------------ +; Custom page function to find the TTDLX CD/install location +Function SelectCDEnter + SectionGetFlags ${Section2} $0 + IntOp $1 $0 & 0x80 ; bit 7 set by upgrade, no need to copy files + IntCmp $1 1 DoneCD ; Upgrade doesn't need copy files + + IntOp $0 $0 & 1 + IntCmp $0 1 NoAbort + Abort +NoAbort: + + GetTempFileName $R0 + !insertmacro MUI_HEADER_TEXT "Locate TTD" "Setup needs the location of Transport Tycoon Deluxe in order to continue." + !insertmacro INSTALLOPTIONS_EXTRACT_AS "CDFinder.ini" "CDFinder" + + ClearErrors + ; Now, let's populate $CDDRIVE + ReadRegStr $R0 HKLM "SOFTWARE\Fish Technology Group\Transport Tycoon Deluxe" "HDPath" + IfErrors NoTTD + StrCmp $CDDRIVE "" 0 Populated + StrCpy $CDDRIVE $R0 +Populated: + StrCpy $AddWinPrePopulate "Setup has detected your TTD folder. Don't change the folder. Simply press Next." + Goto TruFinish +NoTTD: + StrCpy $AddWinPrePopulate "Setup couldn't find TTD. Please enter the path where the graphics files from TTD are stored and press Next to continue." +TruFinish: + ClearErrors + !insertmacro INSTALLOPTIONS_WRITE "CDFinder" "Field 2" "State" $CDDRIVE ; TTDLX path + !insertmacro INSTALLOPTIONS_WRITE "CDFinder" "Field 3" "Text" $AddWinPrePopulate ; Caption +DoneCD: + ; Initialize the dialog *AFTER* we've changed the text otherwise we won't see the changes + !insertmacro INSTALLOPTIONS_INITDIALOG "CDFinder" + !insertmacro INSTALLOPTIONS_SHOW +FunctionEnd + +;---------------------------------------------------------------- +; Custom page function when 'next' is selected for the TTDLX path +Function SelectCDExit + !insertmacro INSTALLOPTIONS_READ $CDDRIVE "CDFinder" "Field 2" "State" + ; If trg1r.grf does not exist at the path, retry with DOS version + IfFileExists $CDDRIVE\trg1r.grf "" DosCD + IfFileExists $CDDRIVE\trgir.grf "" NoCD + IfFileExists $CDDRIVE\sample.cat hasCD NoCD +DosCD: + IfFileExists $CDDRIVE\TRG1.GRF "" NoCD + IfFileExists $CDDRIVE\TRGI.GRF "" NoCD + IfFileExists $CDDRIVE\SAMPLE.CAT hasCD NoCD +NoCD: + MessageBox MB_OK "Setup cannot continue without the Transport Tycoon Deluxe location!" + Abort +hasCD: +FunctionEnd + +;------------------------------------------------------------------------------- +; Determine windows version, returns "win9x" if Win9x/Me/2000/XP SP2- or "winnt" for the rest on the stack +Function GetWindowsVersion + GetVersion::WindowsPlatformArchitecture + Pop $R0 + IntCmp $R0 64 WinNT 0 + ClearErrors + StrCpy $R0 "win9x" + ${If} ${IsNT} + ${If} ${IsWinXP} + ${AndIf} ${AtLeastServicePack} 3 + ${OrIf} ${AtLeastWin2003} + GoTo WinNT + ${EndIf} + ${EndIf} + GoTo Done +WinNT: + StrCpy $R0 "winnt" +Done: + Push $R0 +FunctionEnd + +;------------------------------------------------------------------------------- +; Check whether we're not running an installer for 64 bits on 32 bits and vice versa +Function CheckProcessorArchitecture + GetVersion::WindowsPlatformArchitecture + Pop $R0 + IntCmp $R0 64 Win64 0 + ClearErrors + IntCmp ${APPBITS} 64 0 Done + MessageBox MB_YESNO|MB_ICONSTOP "You are trying to install the 64-bit OpenTTD on a 32-bit operating system. This is not going to work. Please download the correct version. Do you really want to continue?" IDYES Done IDNO Abort + GoTo Done +Win64: + ClearErrors + IntCmp ${APPBITS} 64 Done 0 + MessageBox MB_YESNO|MB_ICONINFORMATION "You are trying to install the 32-bit OpenTTD on a 64-bit operating system. This is not advised, but will work with reduced capabilities. We suggest that you download the correct version. Do you really want to continue?" IDYES Done IDNO Abort + GoTo Done +Abort: + Quit +Done: +FunctionEnd + +;------------------------------------------------------------------------------- +; Check whether we're not running an installer for NT on 9x and vice versa +Function CheckWindowsVersion + Call GetWindowsVersion + Pop $R0 + StrCmp $R0 "win9x" 0 WinNT + ClearErrors + StrCmp ${APPARCH} "win9x" Done 0 + MessageBox MB_YESNO|MB_ICONSTOP "You are trying to install the Windows XP SP3, Vista and 7 version on Windows 95, 98, ME, 2000 and XP without SP3. This is will not work. Please download the correct version. Do you really want to continue?" IDYES Done IDNO Abort + GoTo Done +WinNT: + ClearErrors + StrCmp ${APPARCH} "win9x" 0 Done + MessageBox MB_YESNO|MB_ICONEXCLAMATION "You are trying to install the Windows 95, 98, 2000 and XP without SP3 version on Windows XP SP3, Vista or 7. This is not advised, but will work with reduced capabilities. We suggest that you download the correct version. Do you really want to continue?" IDYES Done IDNO Abort +Abort: + Quit +Done: +FunctionEnd + +;------------------------------------------------------------------------------- +; Check whether OpenTTD is running +Function CheckOpenTTDRunning + IfFileExists "$INSTDIR\openttd.exe" 0 Done +Retry: + FindProcDLL::FindProc "openttd.exe" + Pop $R0 + IntCmp $R0 1 0 Done + ClearErrors + Delete "$INSTDIR\openttd.exe" + IfErrors 0 Done + ClearErrors + MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION "OpenTTD is running. Please close it and retry." IDRETRY Retry + Abort +Done: +FunctionEnd + +;------------------------------------------------------------------------------- +; strips all CRs +; and then converts all LFs into CRLFs +; (this is roughly equivalent to "cat file | dos2unix | unix2dos") +; +; usage: +; Push "infile" +; Call unix2dos +; +; beware that this function destroys $0 $1 $2 +Function unix2dos + ClearErrors + + Pop $2 + Rename $2 $2.U2D + FileOpen $1 $2 w + + FileOpen $0 $2.U2D r + + Push $2 ; save name for deleting + + IfErrors unix2dos_done + + ; $0 = file input (opened for reading) + ; $1 = file output (opened for writing) + +unix2dos_loop: + ; read a byte (stored in $2) + FileReadByte $0 $2 + IfErrors unix2dos_done ; EOL + ; skip CR + StrCmp $2 13 unix2dos_loop + ; if LF write an extra CR + StrCmp $2 10 unix2dos_cr unix2dos_write + +unix2dos_cr: + FileWriteByte $1 13 + +unix2dos_write: + ; write byte + FileWriteByte $1 $2 + ; read next byte + Goto unix2dos_loop + +unix2dos_done: + ; close files + FileClose $0 + FileClose $1 + + ; delete original + Pop $0 + Delete $0.U2D + +FunctionEnd + + +Var OLDVERSION +Var UninstallString + +;----------------------------------------------------------------------------------- +; NSIS Initialize function, determine if we are going to install/upgrade or uninstall +Function .onInit + StrCpy $SHORTCUTS "OpenTTD" + + SectionSetSize ${Section3} 6144 + SectionSetSize ${Section4} 13312 + SectionSetSize ${Section5} 1024 + + SectionSetFlags 0 17 + + ; Starts Setup - let's look for an older version of OpenTTD + ReadRegDWORD $R8 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "Version" + + IfErrors ShowWelcomeMessage ShowUpgradeMessage +ShowWelcomeMessage: + ReadRegStr $R8 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "Version" + ; In the event someone still has OpenTTD 0.1, this will detect that (that installer used a string instead of dword entry) + IfErrors FinishCallback + +ShowUpgradeMessage: + IntCmp ${INSTALLERVERSION} $R8 VersionsAreEqual InstallerIsOlder WelcomeToSetup +WelcomeToSetup: + ; An older version was found. Let's let the user know there's an upgrade that will take place. + ReadRegStr $OLDVERSION HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "DisplayVersion" + ; Gets the older version then displays it in a message box + MessageBox MB_OK|MB_ICONINFORMATION \ + "Welcome to ${APPNAMEANDVERSION} Setup.$\nThis will allow you to upgrade from version $OLDVERSION." + SectionSetFlags ${Section2} 0x80 ; set bit 7 + SectionSetFlags ${Section3} 0x80 ; set bit 7 + SectionSetFlags ${Section4} 0x80 ; set bit 7 + SectionSetFlags ${Section5} 0x80 ; set bit 7 + Goto FinishCallback + +VersionsAreEqual: + ReadRegStr $UninstallString HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "UninstallString" + IfFileExists "$UninstallString" "" FinishCallback + MessageBox MB_YESNO|MB_ICONQUESTION \ + "Setup detected ${APPNAMEANDVERSION} on your system. This is the same version that this program will install.$\nAre you trying to uninstall it?" \ + IDYES DoUninstall IDNO FinishCallback +DoUninstall: ; You have the same version as this installer. This allows you to uninstall. + Exec "$UninstallString" + Quit + +InstallerIsOlder: + MessageBox MB_OK|MB_ICONSTOP \ + "You have a newer version of ${APPNAME}.$\nSetup will now exit." + Quit + +FinishCallback: + ClearErrors + Call CheckProcessorArchitecture + Call CheckWindowsVersion +FunctionEnd +; eof + diff --git a/os/windows/installer/top.bmp b/os/windows/installer/top.bmp new file mode 100644 index 0000000..15a170e Binary files /dev/null and b/os/windows/installer/top.bmp differ diff --git a/os/windows/installer/version_win32.txt b/os/windows/installer/version_win32.txt new file mode 100644 index 0000000..a0aeef5 --- /dev/null +++ b/os/windows/installer/version_win32.txt @@ -0,0 +1,5 @@ +!define APPBITS 32 ; Define number of bits for the architecture +!define EXTRA_VERSION "XP SP3, Vista and 7" +!define APPARCH "win32" ; Define the application architecture +!define BINARY_DIR "${PATH_ROOT}objs\win32\Release" +InstallDir "$PROGRAMFILES32\OpenTTD\" diff --git a/os/windows/installer/version_win64.txt b/os/windows/installer/version_win64.txt new file mode 100644 index 0000000..492a758 --- /dev/null +++ b/os/windows/installer/version_win64.txt @@ -0,0 +1,5 @@ +!define APPBITS 64 ; Define number of bits for the architecture +!define EXTRA_VERSION "XP, Vista and 7" +!define APPARCH "win64" ; Define the application architecture +!define BINARY_DIR "${PATH_ROOT}objs\x64\Release" +InstallDir "$PROGRAMFILES64\OpenTTD\" diff --git a/os/windows/installer/version_win9x.txt b/os/windows/installer/version_win9x.txt new file mode 100644 index 0000000..077390e --- /dev/null +++ b/os/windows/installer/version_win9x.txt @@ -0,0 +1,5 @@ +!define APPBITS 32 ; Define number of bits for the architecture +!define EXTRA_VERSION "95, 98, ME, 2000 and XP without SP3" +!define APPARCH "win9x" ; Define the application architecture +!define BINARY_DIR "${PATH_ROOT}bin" +InstallDir "$PROGRAMFILES32\OpenTTD\" diff --git a/os/windows/installer/welcome.bmp b/os/windows/installer/welcome.bmp new file mode 100644 index 0000000..8df4fa8 Binary files /dev/null and b/os/windows/installer/welcome.bmp differ diff --git a/projects/determineversion.vbs b/projects/determineversion.vbs new file mode 100755 index 0000000..e738569 --- /dev/null +++ b/projects/determineversion.vbs @@ -0,0 +1,365 @@ +Option Explicit + +' $Id$ +' +' This file is part of OpenTTD. +' OpenTTD 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, version 2. +' OpenTTD 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 OpenTTD. If not, see . + +Dim FSO +Set FSO = CreateObject("Scripting.FileSystemObject") + +Sub FindReplaceInFile(filename, to_find, replacement) + Dim file, data + Set file = FSO.OpenTextFile(filename, 1, 0, 0) + data = file.ReadAll + file.Close + data = Replace(data, to_find, replacement) + Set file = FSO.CreateTextFile(filename, -1, 0) + file.Write data + file.Close +End Sub + +Sub UpdateFile(modified, revision, version, cur_date, filename) + FSO.CopyFile filename & ".in", filename + FindReplaceInFile filename, "!!MODIFIED!!", modified + FindReplaceInFile filename, "!!REVISION!!", revision + FindReplaceInFile filename, "!!VERSION!!", version + FindReplaceInFile filename, "!!DATE!!", cur_date +End Sub + +Sub UpdateFiles(version) + Dim modified, revision, cur_date + cur_date = DatePart("D", Date) & "." & DatePart("M", Date) & "." & DatePart("YYYY", Date) + + If InStr(version, Chr(9)) Then + revision = Mid(version, InStr(version, Chr(9)) + 1) + modified = Mid(revision, InStr(revision, Chr(9)) + 1) + revision = Mid(revision, 1, InStr(revision, Chr(9)) - 1) + modified = Mid(modified, 1, InStr(modified, Chr(9)) - 1) + version = Mid(version, 1, InStr(version, Chr(9)) - 1) + Else + revision = 0 + modified = 1 + End If + + UpdateFile modified, revision, version, cur_date, "../src/rev.cpp" + UpdateFile modified, revision, version, cur_date, "../src/os/windows/ottdres.rc" +End Sub + +Function ReadRegistryKey(shive, subkey, valuename, architecture) + Dim hiveKey, objCtx, objLocator, objServices, objReg, Inparams, Outparams + + ' First, get the Registry Provider for the requested architecture + Set objCtx = CreateObject("WbemScripting.SWbemNamedValueSet") + objCtx.Add "__ProviderArchitecture", architecture ' Must be 64 of 32 + Set objLocator = CreateObject("Wbemscripting.SWbemLocator") + Set objServices = objLocator.ConnectServer("","root\default","","",,,,objCtx) + Set objReg = objServices.Get("StdRegProv") + + ' Check the hive and give it the right value + Select Case shive + Case "HKCR", "HKEY_CLASSES_ROOT" + hiveKey = &h80000000 + Case "HKCU", "HKEY_CURRENT_USER" + hiveKey = &H80000001 + Case "HKLM", "HKEY_LOCAL_MACHINE" + hiveKey = &h80000002 + Case "HKU", "HKEY_USERS" + hiveKey = &h80000003 + Case "HKCC", "HKEY_CURRENT_CONFIG" + hiveKey = &h80000005 + Case "HKDD", "HKEY_DYN_DATA" ' Only valid for Windows 95/98 + hiveKey = &h80000006 + Case Else + MsgBox "Hive not valid (ReadRegistryKey)" + End Select + + Set Inparams = objReg.Methods_("GetStringValue").Inparameters + Inparams.Hdefkey = hiveKey + Inparams.Ssubkeyname = subkey + Inparams.Svaluename = valuename + Set Outparams = objReg.ExecMethod_("GetStringValue", Inparams,,objCtx) + + ReadRegistryKey = Outparams.SValue +End Function + +Function DetermineSVNVersion() + Dim WshShell, version, branch, modified, revision, clean_rev, url, oExec, line, hash + Set WshShell = CreateObject("WScript.Shell") + On Error Resume Next + + revision = 0 + + ' Try TortoiseSVN + ' Get the directory where TortoiseSVN (should) reside(s) + Dim sTortoise + ' First, try with 32-bit architecture + sTortoise = ReadRegistryKey("HKLM", "SOFTWARE\TortoiseSVN", "Directory", 32) + If sTortoise = "" Or IsNull(sTortoise) Then + ' No 32-bit version of TortoiseSVN installed, try 64-bit version (doesn't hurt on 32-bit machines, it returns nothing or is ignored) + sTortoise = ReadRegistryKey("HKLM", "SOFTWARE\TortoiseSVN", "Directory", 64) + End If + + ' If TortoiseSVN is installed, try to get the revision number + If sTortoise <> "" Then + Dim SubWCRev + Set SubWCRev = WScript.CreateObject("SubWCRev.object") + SubWCRev.GetWCInfo FSO.GetAbsolutePathName("../"), 0, 0 + revision = SubWCRev.Revision + version = "r" & revision + modified = 0 + if SubWCRev.HasModifications then modified = 2 + url = SubWCRev.Url + End If + + ' Looks like there is no TortoiseSVN installed either. Then we don't know it. + If revision = 0 Then + ' Reset error and version + Err.Clear + version = "norev000" + modified = 0 + + ' Set the environment to english + WshShell.Environment("PROCESS")("LANG") = "en" + + ' Do we have subversion installed? Check immediatelly whether we've got a modified WC. + Set oExec = WshShell.Exec("svnversion ../") + If Err.Number = 0 Then + ' Wait till the application is finished ... + Do While oExec.Status = 0 + Loop + + line = OExec.StdOut.ReadLine() + If line <> "exported" Then + If InStr(line, "M") Then + modified = 2 + End If + + ' And use svn info to get the correct revision and branch information. + Set oExec = WshShell.Exec("svn info ../") + If Err.Number = 0 Then + Do + line = OExec.StdOut.ReadLine() + If InStr(line, "URL") Then + url = line + End If + If InStr(line, "Last Changed Rev") Then + revision = Mid(line, 19) + version = "r" & revision + End If + Loop While Not OExec.StdOut.atEndOfStream + End If ' Err.Number = 0 + End If ' line <> "exported" + End If ' Err.Number = 0 + End If ' InStr(version, "$") + + If version <> "norev000" Then + If InStr(url, "branches") Then + branch = Mid(url, InStr(url, "branches/") + 9) + End If + If InStr(url, "tags") Then + version = Mid(url, InStr(url, "tags/") + 5) + End If + Else ' version <> "norev000" + ' svn detection failed, reset error and try git + Err.Clear + Set oExec = WshShell.Exec("git rev-parse --verify HEAD") + If Err.Number = 0 Then + ' Wait till the application is finished ... + Do While oExec.Status = 0 + Loop + + If oExec.ExitCode = 0 Then + hash = oExec.StdOut.ReadLine() + version = "g" & Mid(hash, 1, 8) + ' Make sure index is in sync with disk + Set oExec = WshShell.Exec("git update-index --refresh") + If Err.Number = 0 Then + ' StdOut and StdErr share a 4kB buffer so prevent it from filling up as we don't care about the output + oExec.StdOut.Close + oExec.StdErr.Close + ' Wait till the application is finished ... + Do While oExec.Status = 0 + WScript.Sleep 10 + Loop + End If + Set oExec = WshShell.Exec("git diff-index --exit-code --quiet HEAD ../") + If Err.Number = 0 Then + ' Wait till the application is finished ... + Do While oExec.Status = 0 + Loop + + If oExec.ExitCode = 1 Then + modified = 2 + End If ' oExec.ExitCode = 1 + + Set oExec = WshShell.Exec("git symbolic-ref HEAD") + If Err.Number = 0 Then + line = oExec.StdOut.ReadLine() + line = Mid(line, InStrRev(line, "/") + 1) + If line <> "master" Then + branch = line + End If ' line <> "master" + End If ' Err.Number = 0 + + Set oExec = WshShell.Exec("git log --pretty=format:%s --grep=" & Chr(34) & "^(svn r[0-9]*)" & Chr(34) & " -1") + if Err.Number = 0 Then + revision = Mid(oExec.StdOut.ReadLine(), 7) + revision = Mid(revision, 1, InStr(revision, ")") - 1) + End If ' Err.Number = 0 + If revision = "" Then + ' No revision? Maybe it is a custom git-svn clone + ' Reset error number as WshShell.Exec will not do that on success + Err.Clear + Set oExec = WshShell.Exec("git log --pretty=format:%b --grep=" & Chr(34) & "git-svn-id:.*@[0-9]*" & Chr(34) & " -1") + If Err.Number = 0 Then + revision = oExec.StdOut.ReadLine() + revision = Mid(revision, InStr(revision, "@") + 1) + revision = Mid(revision, 1, InStr(revision, " ") - 1) + End If ' Err.Number = 0 + End If ' revision = "" + + ' Check if a tag is currently checked out + Err.Clear + Set oExec = WshShell.Exec("git name-rev --name-only --tags --no-undefined HEAD") + If Err.Number = 0 Then + ' Wait till the application is finished ... + Do While oExec.Status = 0 + Loop + If oExec.ExitCode = 0 Then + version = oExec.StdOut.ReadLine() + If Right(version, 2) = "^0" Then + version = Left(version, Len(version) - 2) + End If + branch = "" + End If ' oExec.ExitCode = 0 + End If ' Err.Number = 0 + End If ' Err.Number = 0 + End If ' oExec.ExitCode = 0 + End If ' Err.Number = 0 + + If version = "norev000" Then + ' git detection failed, reset error and try mercurial (hg) + Err.Clear + Set oExec = WshShell.Exec("hg id -i") + If Err.Number = 0 Then + ' Wait till the application is finished ... + Do While oExec.Status = 0 + Loop + + If oExec.ExitCode = 0 Then + line = OExec.StdOut.ReadLine() + hash = Left(line, 12) + version = "h" & Mid(hash, 1, 8) + + ' Check if a tag is currently checked out + Err.Clear + Set oExec = WshShell.Exec("hg id -t") + If Err.Number = 0 Then + line = oExec.StdOut.ReadLine() + If Len(line) > 0 And Right(line, 3) <> "tip" Then + version = line + branch = "" + End If ' Len(line) > 0 And Right(line, 3) <> "tip" + End If ' Err.Number = 0 + + Err.Clear + Set oExec = WshShell.Exec("hg status ../") + If Err.Number = 0 Then + Do + line = OExec.StdOut.ReadLine() + If Len(line) > 0 And Mid(line, 1, 1) <> "?" Then + modified = 2 + Exit Do + End If ' Len(line) > 0 And Mid(line, 1, 1) <> "?" + Loop While Not OExec.StdOut.atEndOfStream + + Set oExec = WshShell.Exec("hg branch") + If Err.Number = 0 Then + line = OExec.StdOut.ReadLine() + If line <> "default" Then + branch = line + End If ' line <> "default" + End If ' Err.Number = 0 + + Set oExec = WshShell.Exec("hg log -f -k " & Chr(34) & "(svn r" & Chr(34) & " -l 1 --template " & Chr(34) & "{desc|firstline}\n" & Chr(34) & " --cwd ../") + If Err.Number = 0 Then + line = oExec.StdOut.ReadLine() + If Left(line, 6) = "(svn r" Then + revision = Mid(line, 7) + revision = Mid(revision, 1, InStr(revision, ")") - 1) + End If 'Left(line, 6) = "(svn r" + End If ' Err.Number = 0 + + If revision = "" Then + ' No rev? Maybe it is a custom hgsubversion clone + Err.Clear + Set oExec = WshShell.Exec("hg parent --template=" & Chr(34) & "{svnrev}" & Chr(34)) + If Err.Number = 0 Then + revision = oExec.StdOut.ReadLine() + End If ' Err.Number = 0 + End If ' revision = "" + End If ' Err.Number = 0 + End If ' oExec.ExitCode = 0 + End If ' Err.Number = 0 + End If ' version = "norev000" + End If ' version <> "norev000" + + If version = "norev000" And FSO.FileExists("../.ottdrev") Then + Dim rev_file + Set rev_file = FSO.OpenTextFile("../.ottdrev", 1, True, 0) + DetermineSVNVersion = rev_file.ReadLine() + rev_file.Close() + Else + If modified = 2 Then + version = version & "M" + End If + + clean_rev = version + If branch <> "" Then + version = version & "-" & branch + End If + + If version <> "norev000" Then + DetermineSVNVersion = version & Chr(9) & revision & Chr(9) & modified & Chr(9) & clean_rev + Else + DetermineSVNVersion = version + End If + End If +End Function + +Function IsCachedVersion(ByVal version) + Dim cache_file, cached_version + cached_version = "" + Set cache_file = FSO.OpenTextFile("../config.cache.version", 1, True, 0) + If Not cache_file.atEndOfStream Then + cached_version = cache_file.ReadLine() + End If + cache_file.Close + + If InStr(version, Chr(9)) Then + version = Mid(version, 1, Instr(version, Chr(9)) - 1) + End If + + If version <> cached_version Then + Set cache_file = fso.CreateTextFile("../config.cache.version", True) + cache_file.WriteLine(version) + cache_file.Close + IsCachedVersion = False + Else + IsCachedVersion = True + End If +End Function + +Function CheckFile(filename) + CheckFile = FSO.FileExists(filename) + If CheckFile Then CheckFile = (FSO.GetFile(filename).DateLastModified >= FSO.GetFile(filename & ".in").DateLastModified) +End Function + +Dim version +version = DetermineSVNVersion +If Not (IsCachedVersion(version) And CheckFile("../src/rev.cpp") And CheckFile("../src/os/windows/ottdres.rc")) Then + UpdateFiles version +End If diff --git a/projects/generate b/projects/generate new file mode 100755 index 0000000..42b684d --- /dev/null +++ b/projects/generate @@ -0,0 +1,316 @@ +#!/bin/bash + +# $Id$ + +# This file is part of OpenTTD. +# OpenTTD 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, version 2. +# OpenTTD 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 OpenTTD. If not, see . + +# This file generates all project files based on sources.list, so everyone who +# can start a bash process, can update the project files. + +ROOT_DIR="`pwd`/.." +if ! [ -e "$ROOT_DIR/source.list" ] +then + ROOT_DIR="`pwd`" +fi +if ! [ -e "$ROOT_DIR/source.list" ] +then + echo "Can't find source.list, needed in order to make this run. Please go to either" + echo " the project dir, or the root dir of a clean SVN checkout." + exit 1 +fi + +# openttd_vs100.sln is for MSVC 2010 +# openttd_vs100.vcxproj is for MSVC 2010 +# openttd_vs100.vcxproj.filters is for MSVC 2010 +# langs_vs100.vcxproj is for MSVC 2010 +# strgen_vs100.vcxproj is for MSVC 2010 +# strgen_vs100.vcxproj.filters is for MSVC 2010 +# generate_vs100.vcxproj is for MSVC 2010 +# version_vs100.vcxproj is for MSVC 2010 + +# openttd_vs90.sln is for MSVC 2008 +# openttd_vs90.vcproj is for MSVC 2008 +# langs_vs90.vcproj is for MSVC 2008 +# strgen_vs90.vcproj is for MSVC 2008 +# generate_vs90.vcproj is for MSVC 2008 +# version_vs90.vcproj is for MSVC 2008 + +# openttd_vs80.sln is for MSVC 2005 +# openttd_vs80.vcproj is for MSVC 2005 +# langs_vs80.vcproj is for MSVC 2005 +# strgen_vs80.vcproj is for MSVC 2005 +# generate_vs80.vcproj is for MSVC 2005 +# version_vs80.vcproj is for MSVC 2005 + + + +# First, collect the list of Windows files +allegro_config="" +sdl_config="1" +png_config="1" +os="MSVC" +enable_dedicated="0" +enable_ai="1" +with_cocoa="0" +enable_directmusic="1" +with_threads="1" +file_prefix="..\\\\src\\\\" + +safety_check() { + li="" + for i in `cat $1 | grep -v "#\|ottdres.rc\|win32.cpp\|win32_v.cpp" | xargs -n 1 basename | sort`; do + if [ "$li" = "$i" ]; then + echo " !! ERROR !!" + echo "" + echo "The filename '$i' is already used in this project." + echo "Because MSVC uses one single directory for all object files, it" + echo "cannot handle filenames with the same name inside the same project." + echo "Please rename either one of the file and try generating again." + echo "" + echo " !! ERROR !!" + exit 1 + fi + li="$i" + done +} + +grep '\.h' "$ROOT_DIR/source.list" | grep -v '../objs/langs/table/strings.h\|../objs/settings/table/settings.h' | sed 's/ //g' | sort > tmp.headers.source.list +find "$ROOT_DIR/src" \( -iname "*.h" -or -iname "*.hpp" \) -and -not -ipath "*/.svn/*" | sed "s~$ROOT_DIR/src/~~" | sort > tmp.headers.src +if [ -n "`diff tmp.headers.source.list tmp.headers.src`" ]; then + echo "The following headers are missing in source.list and not in /src/ or vice versa." + diff tmp.headers.source.list tmp.headers.src | grep '[<>]' | sort + echo "" +fi +rm tmp.headers.* + +load_main_data() { + # Read the source.list and process it + RES="`cat $1 | tr '\r' '\n' | awk ' + /^( *)#end/ { if (deep == skip) { skip -= 1; } deep -= 1; next; } + /^( *)#else/ { if (deep == skip) { skip -= 1; } else if (deep - 1 == skip) { skip += 1; } next; } + /^( *)#if/ { + gsub(" ", "", $0); + gsub("^#if", "", $0); + gsub("^ ", "", $0); + + if (deep != skip) { deep += 1; next; } + + deep += 1; + + if ($0 == "ALLEGRO" && "'$allegro_config'" == "") { next; } + if ($0 == "SDL" && "'$sdl_config'" == "") { next; } + if ($0 == "PNG" && "'$png_config'" == "") { next; } + if ($0 == "OSX" && "'$os'" != "OSX") { next; } + if ($0 == "OS2" && "'$os'" != "OS2") { next; } + if ($0 == "PSP" && "'$os'" != "PSP") { next; } + if ($0 == "DOS" && "'$os'" != "DOS") { next; } + if ($0 == "DEDICATED" && "'$enable_dedicated'" != "1") { next; } + if ($0 == "AI" && "'$enable_ai'" == "0") { next; } + if ($0 == "COCOA" && "'$with_cocoa'" == "0") { next; } + if ($0 == "BEOS" && "'$os'" != "BEOS") { next; } + if ($0 == "WIN32" && "'$os'" != "MINGW" && + "'$os'" != "CYGWIN" && "'$os'" != "MSVC" ) { next; } + if ($0 == "WINCE" && "'$os'" != "WINCE") { next; } + if ($0 == "MSVC" && "'$os'" != "MSVC") { next; } + if ($0 == "DIRECTMUSIC" && "'$enable_directmusic'" != "1") { next; } + if ($0 == "LIBTIMIDITY" && "'$libtimidity'" == "" ) { next; } + if ($0 == "HAVE_THREAD" && "'$with_threads'" == "0") { next; } + + skip += 1; + + next; + } + /^( *)#/ { + if (deep == skip) { + gsub(" ", "", $0); + gsub("^#", "", $0); + gsub("^ ", "", $0); + + if (first_time != 0) { + print "#1 "; + } else { + first_time = 1; + } + + filter = $0; + print "#1 "; + print "#3 "; + printf "#3 {c76ff9f1-1e62-46d8-8d55-%012d}\n", i; + print "#3 "; + i += 1; + } + + next; + } + /^$/ { next } + { + if (deep == skip) { + gsub(" ", "", $0); + gsub("/", "\\\\", $0); + print "#1 "; + print "#1 "; + split($0, file, "."); + cltype = "ClInclude" + if (file[2] == "cpp") cltype = "ClCompile"; + if (file[2] == "rc") cltype = "ResourceCompile"; + print "#2 <"cltype" Include=\\"'$file_prefix'"$0"\\" />"; + print "#4 <"cltype" Include=\\"'$file_prefix'"$0"\\">"; + print "#4 "filter""; + print "#4 "; + } + } + END { print "#1 "; } + '`" + + eval "$2=\"\$RES\"" +} + +load_lang_data() { + RES="" + for i in `ls $1` + do + i=`basename $i | sed s~.txt$~~g` + if [ "$i" == "english" ] + then + continue + fi + RES="$RES +#1 +#1 +#1 +#1 +#1 +#2 +#2 Generating "$i" language file +#2 ..\\objs\\strgen\\strgen.exe -s ..\\src\\lang -d ..\\bin\\lang \"%(FullPath)\" +#2 ..\\src\\lang\\english.txt;..\\objs\\strgen\\strgen.exe;%(AdditionalInputs) +#2 ..\\bin\\lang\\"$i".lng;%(Outputs) +#2 +#3 +#3 Translations +#3 " + done + + eval "$2=\"\$RES\"" +} + +load_settings_data() { + RES="" + RES2=" +#3..\\objs\\settings\\settings_gen.exe -o ..\\objs\\settings\\table\\settings.h -b ..\\src\\table\\settings.h.preamble -a ..\\src\\table\\settings.h.postamble" + for i in `ls $1` + do + i=`basename $i` + RES="$RES +#1 +#1 +#2 +#4 +#4 INI +#4 " + RES2="$RES2 ..\\src\\table\\"$i + done + + eval "$2=\"\$RES\$RES2\"" +} + +generate() { + echo "Generating $2..." + if [ $# -eq 3 ]; then + # Everything above the !!FILTERS!! marker + cat "$ROOT_DIR/projects/$2".in | tr '\r' '\n' | awk ' + /^$/ { next } + /!!FILTERS!!/ { stop = 1; } + { + if (stop == 0) { print $0 } + } + ' > "$ROOT_DIR/projects/$2" + + echo "$3" >> "$ROOT_DIR/projects/$2" + + # Everything below the !!FILTERS!! marker and above the !!FILES!! marker + cat "$ROOT_DIR/projects/$2".in | tr '\r' '\n' | awk ' + BEGIN { stop = 1; } + /^$/ { next } + /!!FILTERS!!/ { stop = 2; } + /!!FILES!!/ { stop = 1; } + { + if (stop == 0) { print $0 } + if (stop == 2) { stop = 0 } + } + ' >> "$ROOT_DIR/projects/$2" + else + # Everything above the !!FILES!! marker + cat "$ROOT_DIR/projects/$2".in | tr '\r' '\n' | awk ' + /^$/ { next } + /!!FILES!!/ { stop = 1; } + { + if (stop == 0) { print $0 } + } + ' > "$ROOT_DIR/projects/$2" + fi + + echo "$1" >> "$ROOT_DIR/projects/$2" + + # Everything below the !!FILES!! marker + cat "$ROOT_DIR/projects/$2".in | tr '\r' '\n' | awk ' + BEGIN { stop = 1; } + /^$/ { next } + /!!FILES!!/ { stop = 2; } + { + if (stop == 0) { print $0 } + if (stop == 2) { stop = 0 } + } + ' >> "$ROOT_DIR/projects/$2" +} + +safety_check "$ROOT_DIR/source.list" + +load_main_data "$ROOT_DIR/source.list" openttd +openttdfiles=`echo "$openttd" | grep "^#4" | sed "s~#4~~g"` +openttdfilters=`echo "$openttd" | grep "^#3" | sed "s~#3~~g"` +openttdvcxproj=`echo "$openttd" | grep "^#2" | sed "s~#2~~g"` +openttd=`echo "$openttd" | grep "^#1" | sed "s~#1~~g"` + +load_lang_data "$ROOT_DIR/src/lang/*.txt" lang +langfiles=`echo "$lang" | grep "^#3" | sed "s~#3~~g"` +langvcxproj=`echo "$lang" | grep "^#2" | sed "s~#2~~g"` +lang=`echo "$lang" | grep "^#1" | sed "s~#1~~g"` + +load_settings_data "$ROOT_DIR/src/table/*.ini" settings +settingsfiles=`echo "$settings" | grep "^#4" | sed "s~#4~~g"` +settingscommand=`echo "$settings" | grep "^#3" | sed "s~#3~~g"` +settingsvcxproj=`echo "$settings" | grep "^#2" | sed "s~#2~~g"` +settings=`echo "$settings" | grep "^#1" | sed "s~#1~~g"` + +generate "$openttd" "openttd_vs80.vcproj" +generate "$openttd" "openttd_vs90.vcproj" +generate "$openttdvcxproj" "openttd_vs100.vcxproj" +generate "$openttdfiles" "openttd_vs100.vcxproj.filters" "$openttdfilters" +generate "$lang" "langs_vs80.vcproj" +generate "$lang" "langs_vs90.vcproj" +generate "$langvcxproj" "langs_vs100.vcxproj" +generate "$langfiles" "langs_vs100.vcxproj.filters" +generate "$settings" "settings_vs80.vcproj" "$settingscommand" +generate "$settings" "settings_vs90.vcproj" "$settingscommand" +generate "$settingsvcxproj" "settings_vs100.vcxproj" "$settingscommand" +generate "$settingsfiles" "settings_vs100.vcxproj.filters" diff --git a/projects/generate.vbs b/projects/generate.vbs new file mode 100755 index 0000000..4e1e886 --- /dev/null +++ b/projects/generate.vbs @@ -0,0 +1,385 @@ +Option Explicit + +' $Id$ +' +' This file is part of OpenTTD. +' OpenTTD 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, version 2. +' OpenTTD 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 OpenTTD. If not, see . + +Dim FSO +Set FSO = CreateObject("Scripting.FileSystemObject") + +' openttd_vs100.sln is for MSVC 2010 +' openttd_vs100.vcxproj is for MSVC 2010 +' openttd_vs100.vcxproj.filters is for MSVC 2010 +' langs_vs100.vcxproj is for MSVC 2010 +' strgen_vs100.vcxproj is for MSVC 2010 +' strgen_vs100.vcxproj.filters is for MSVC 2010 +' generate_vs100.vcxproj is for MSVC 2010 +' version_vs100.vcxproj is for MSVC 2010 + +' openttd_vs90.sln is for MSVC 2008 +' openttd_vs90.vcproj is for MSVC 2008 +' langs_vs90.vcproj is for MSVC 2008 +' strgen_vs90.vcproj is for MSVC 2008 +' generate_vs90.vcproj is for MSVC 2008 +' version_vs90.vcproj is for MSVC 2008 + +' openttd_vs80.sln is for MSVC 2005 +' openttd_vs80.vcproj is for MSVC 2005 +' langs_vs80.vcproj is for MSVC 2005 +' strgen_vs80.vcproj is for MSVC 2005 +' generate_vs80.vcproj is for MSVC 2005 +' version_vs80.vcproj is for MSVC 2005 + +Sub safety_check(filename) + Dim file, line, regexp, list + + ' Define regexp + Set regexp = New RegExp + regexp.Pattern = "#|ottdres.rc|win32.cpp|win32_v.cpp" + regexp.Global = True + + ' We use a dictionary to check duplicates + Set list = CreateObject("Scripting.Dictionary") + + Set file = FSO.OpenTextFile(filename, 1, 0, 0) + While Not file.AtEndOfStream + line = Replace(file.ReadLine, Chr(9), "") ' Remove tabs + If Len(line) > 0 And Not regexp.Test(line) Then + line = FSO.GetFileName(line) + if list.Exists(line) Then + WScript.Echo " !! ERROR !!" _ + & vbCrLf & "" _ + & vbCrLf & "The filename '" & line & "' is already used in this project." _ + & vbCrLf & "Because MSVC uses one single directory for all object files, it" _ + & vbCrLf & "cannot handle filenames with the same name inside the same project." _ + & vbCrLf & "Please rename either one of the file and try generating again." _ + & vbCrLf & "" _ + & vbCrLf & " !! ERROR !!" + WScript.Quit(1) + End If + list.Add line, line + End If + Wend + file.Close +End Sub + +Sub get_files(srcdir, dir, list) + Dim file, filename + Dim rekeep, reskip + + ' pattern for files to keep + Set rekeep = New RegExp + rekeep.Pattern = "\.h(pp)?$" + rekeep.Global = True + + ' pattern for files to exclude + Set reskip = New RegExp + reskip.Pattern = "\.svn" + reskip.Global = True + + For Each file in dir.Files + filename = Replace(file.path, srcdir, "") ' Remove */src/ + filename = Replace(filename, "\", "/") ' Replace separators + If rekeep.Test(filename) And Not reskip.Test(filename) Then + list.Add filename, filename + End If + Next +End Sub + +Sub get_dir_files(srcdir, dir, list) + Dim folder + ' Get files + get_files srcdir, dir, list + + ' Recurse in subfolders + For Each folder in dir.SubFolders + get_dir_files srcdir, folder, list + Next +End Sub + +Sub headers_check(filename, dir) + Dim source_list_headers, src_dir_headers, regexp, line, file, str + + ' Define regexp for source.list parsing + Set regexp = New RegExp + regexp.Pattern = "\.h" + regexp.Global = True + + ' Parse source.list and store headers in a dictionary + Set source_list_headers = CreateObject("Scripting.Dictionary") + Set file = FSO.OpenTextFile(filename, 1, 0, 0) + While Not file.AtEndOfStream + line = Replace(file.ReadLine, Chr(9), "") ' Remove tabs + If Len(line) > 0 And regexp.Test(line) And line <> "../objs/langs/table/strings.h" And line <> "../objs/settings/table/settings.h" Then + source_list_headers.Add line, line + End If + Wend + file.Close() + + ' Get header files in /src/ + Set src_dir_headers = CreateObject("Scripting.Dictionary") + get_dir_files dir, FSO.GetFolder(dir), src_dir_headers + + ' Finding files in source.list but not in /src/ + For Each line In source_list_headers + If Not src_dir_headers.Exists(line) Then + str = str & "< " & line & vbCrLf + End If + Next + + ' Finding files in /src/ but not in source.list + For Each line In src_dir_headers + If Not source_list_headers.Exists(line) Then + str = str & "> " & line & vbCrLf + End If + Next + + ' Display the missing files if any + If str <> "" Then + str = "The following headers are missing in source.list and not in /src/ or vice versa." _ + & vbCrLf & str + WScript.Echo str + End If +End Sub + +Function load_main_data(filename, ByRef vcxproj, ByRef filters, ByRef files) + Dim res, file, line, deep, skip, first_filter, first_file, filter, cltype, index + res = "" + index = 0 + ' Read the source.list and process it + Set file = FSO.OpenTextFile(filename, 1, 0, 0) + While Not file.AtEndOfStream + line = Replace(file.ReadLine, Chr(9), "") ' Remove tabs + If Len(line) > 0 Then + Select Case Split(line, " ")(0) + Case "#end" + If deep = skip Then skip = skip - 1 + deep = deep - 1 + Case "#else" + If deep = skip Then + skip = skip - 1 + ElseIf deep - 1 = skip Then + skip = skip + 1 + End If + Case "#if" + line = Replace(line, "#if ", "") + If deep = skip And ( _ + line = "SDL" Or _ + line = "PNG" Or _ + line = "WIN32" Or _ + line = "MSVC" Or _ + line = "DIRECTMUSIC" Or _ + line = "AI" Or _ + line = "SSE" Or _ + line = "HAVE_THREAD" _ + ) Then skip = skip + 1 + deep = deep + 1 + Case "#" + if deep = skip Then + line = Replace(line, "# ", "") + if first_filter <> 0 Then + res = res & " " & vbCrLf + filters = filters & vbCrLf + Else + first_filter = 1 + End If + filter = line + res = res & _ + " " & vbCrLf + filters = filters & _ + " " & vbCrLf & _ + " {c76ff9f1-1e62-46d8-8d55-" & String(12 - Len(CStr(index)), "0") & index & "}" & vbCrLf & _ + " " + index = index + 1 + End If + Case Else + If deep = skip Then + line = Replace(line, "/" ,"\") + if first_file <> 0 Then + vcxproj = vcxproj & vbCrLf + files = files & vbCrLf + Else + first_file = 1 + End If + res = res & _ + " " & vbCrLf & _ + " " & vbCrLf + Select Case Split(Line, ".")(1) + Case "cpp" + cltype = "ClCompile" + Case "rc" + cltype = "ResourceCompile" + Case Else + cltype = "ClInclude" + End Select + vcxproj = vcxproj & " <" & cltype & " Include="& Chr(34) & "..\src\" & line & Chr(34) & " />" + files = files & _ + " <" & cltype & " Include="& Chr(34) & "..\src\" & line & Chr(34) & ">" & vbCrLf & _ + " " & filter & "" & vbCrLf & _ + " " + End If + End Select + End If + Wend + res = res & " " + file.Close() + load_main_data = res +End Function + +Function load_lang_data(dir, ByRef vcxproj, ByRef files) + Dim res, folder, file, first_time + res = "" + Set folder = FSO.GetFolder(dir) + For Each file In folder.Files + file = FSO.GetFileName(file) + If file <> "english.txt" And FSO.GetExtensionName(file) = "txt" Then + file = Left(file, Len(file) - 4) + If first_time <> 0 Then + res = res & vbCrLf + vcxproj = vcxproj & vbCrLf + files = files & vbCrLf + Else + first_time = 1 + End If + res = res & _ + " " & vbCrLf & _ + " " & vbCrLf & _ + " " & vbCrLf & _ + " " & vbCrLf & _ + " " + vcxproj = vcxproj & _ + " " & vbCrLf & _ + " Generating " & file & " language file" & vbCrLf & _ + " ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang " & Chr(34) & "%(FullPath)" & Chr(34) & "" & vbCrLf & _ + " ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs)" & vbCrLf & _ + " ..\bin\lang\" & file & ".lng;%(Outputs)" & vbCrLf & _ + " " + files = files & _ + " " & vbCrLf & _ + " Translations" & vbCrLf & _ + " " + End If + Next + load_lang_data = res +End Function + +Function load_settings_data(dir, ByRef vcxproj, ByRef command, ByRef files) + Dim res, folder, file, first_time + res = "" + command = "..\objs\settings\settings_gen.exe -o ..\objs\settings\table\settings.h -b ..\src\table\settings.h.preamble -a ..\src\table\settings.h.postamble" + Set folder = FSO.GetFolder(dir) + For Each file In folder.Files + file = FSO.GetFileName(file) + If FSO.GetExtensionName(file) = "ini" Then + if first_time <> 0 Then + res = res & vbCrLf + vcxproj = vcxproj & vbCrLf + files = files & vbCrLf + Else + first_time = 1 + End If + res = res & _ + " " & vbCrLf & _ + " " + vcxproj = vcxproj & _ + " " + command = command & " ..\src\table\" & file + files = files & _ + " " & vbCrLf & _ + " INI" & vbCrLf & _ + " " + End If + Next + load_settings_data = res +End Function + +Sub generate(data, dest, data2) + Dim srcfile, destfile, line + WScript.Echo "Generating " & FSO.GetFileName(dest) & "..." + Set srcfile = FSO.OpenTextFile(dest & ".in", 1, 0, 0) + Set destfile = FSO.CreateTextFile(dest, -1, 0) + + If Not IsNull(data2) Then + ' Everything above the !!FILTERS!! marker + line = srcfile.ReadLine() + While line <> "!!FILTERS!!" + If len(line) > 0 Then destfile.WriteLine(line) + line = srcfile.ReadLine() + Wend + + ' Our generated content + destfile.WriteLine(data2) + End If + + ' Everything above the !!FILES!! marker + line = srcfile.ReadLine() + While line <> "!!FILES!!" + If len(line) > 0 Then destfile.WriteLine(line) + line = srcfile.ReadLine() + Wend + + ' Our generated content + destfile.WriteLine(data) + + ' Everything below the !!FILES!! marker + While Not srcfile.AtEndOfStream + line = srcfile.ReadLine() + If len(line) > 0 Then destfile.WriteLine(line) + Wend + srcfile.Close() + destfile.Close() +End Sub + +Dim ROOT_DIR +ROOT_DIR = FSO.GetFolder("..").Path +If Not FSO.FileExists(ROOT_DIR & "/source.list") Then + ROOT_DIR = FSO.GetFolder(".").Path +End If +If Not FSO.FileExists(ROOT_DIR & "/source.list") Then + WScript.Echo "Can't find source.list, needed in order to make this run." _ + & vbCrLf & "Please go to either the project dir, or the root dir of a clean SVN checkout." + WScript.Quit(1) +End If + +safety_check ROOT_DIR & "/source.list" +headers_check ROOT_DIR & "/source.list", ROOT_DIR & "\src\" ' Backslashes needed for DoFiles + +Dim openttd, openttdvcxproj, openttdfilters, openttdfiles +openttd = load_main_data(ROOT_DIR & "/source.list", openttdvcxproj, openttdfilters, openttdfiles) +generate openttd, ROOT_DIR & "/projects/openttd_vs80.vcproj", Null +generate openttd, ROOT_DIR & "/projects/openttd_vs90.vcproj", Null +generate openttdvcxproj, ROOT_DIR & "/projects/openttd_vs100.vcxproj", Null +generate openttdfiles, ROOT_DIR & "/projects/openttd_vs100.vcxproj.filters", openttdfilters + +Dim lang, langvcxproj, langfiles +lang = load_lang_data(ROOT_DIR & "/src/lang", langvcxproj, langfiles) +generate lang, ROOT_DIR & "/projects/langs_vs80.vcproj", Null +generate lang, ROOT_DIR & "/projects/langs_vs90.vcproj", Null +generate langvcxproj, ROOT_DIR & "/projects/langs_vs100.vcxproj", Null +generate langfiles, ROOT_DIR & "/projects/langs_vs100.vcxproj.filters", Null + +Dim settings, settingsvcxproj, settingscommand, settingsfiles +settings = load_settings_data(ROOT_DIR & "/src/table", settingsvcxproj, settingscommand, settingsfiles) +generate settings, ROOT_DIR & "/projects/settings_vs80.vcproj", settingscommand +generate settings, ROOT_DIR & "/projects/settings_vs90.vcproj", settingscommand +generate settingsvcxproj, ROOT_DIR & "/projects/settings_vs100.vcxproj", settingscommand +generate settingsfiles, ROOT_DIR & "/projects/settings_vs100.vcxproj.filters", Null diff --git a/projects/generate_vs100.vcxproj b/projects/generate_vs100.vcxproj new file mode 100644 index 0000000..17552c0 --- /dev/null +++ b/projects/generate_vs100.vcxproj @@ -0,0 +1,43 @@ + + + + + Debug + Win32 + + + + generate + {2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34} + generate + + + + Utility + v140 + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + + + + + + Document + Running %27generate.vbs%27 ... + cscript "$(ProjectDir)generate.vbs" + %(FullPath);%(AdditionalInputs) + $(SolutionDir)openttd_vs80.vcproj;$(SolutionDir)openttd_vs90.vcproj;$(SolutionDir)openttd_vs100.vcxproj;$(SolutionDir)openttd_vs100.vcxproj.filters;$(SolutionDir)langs_vs80.vcproj;$(SolutionDir)langs_vs90.vcproj;$(SolutionDir)langs_vs100.vcxproj;%(Outputs) + + + + + + \ No newline at end of file diff --git a/projects/generate_vs80.vcproj b/projects/generate_vs80.vcproj new file mode 100644 index 0000000..bc0b6c4 --- /dev/null +++ b/projects/generate_vs80.vcproj @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + diff --git a/projects/generate_vs90.vcproj b/projects/generate_vs90.vcproj new file mode 100644 index 0000000..dc7b3e2 --- /dev/null +++ b/projects/generate_vs90.vcproj @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + diff --git a/projects/langs_vs100.vcxproj b/projects/langs_vs100.vcxproj new file mode 100644 index 0000000..078a7b3 --- /dev/null +++ b/projects/langs_vs100.vcxproj @@ -0,0 +1,384 @@ + + + + + Debug + Win32 + + + + langs + {0F066B23-18DF-4284-8265-F4A5E7E3B966} + langs + MakeFileProj + + + + Utility + false + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\bin\lang\ + ..\objs\langs\ + + + + Generating strings.h + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\objs\langs\table + + + ./langs.tlb + + + + + + + Generating english language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\english.lng;%(Outputs) + + + Generating afrikaans language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\afrikaans.lng;%(Outputs) + + + Generating arabic_egypt language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\arabic_egypt.lng;%(Outputs) + + + Generating basque language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\basque.lng;%(Outputs) + + + Generating belarusian language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\belarusian.lng;%(Outputs) + + + Generating brazilian_portuguese language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\brazilian_portuguese.lng;%(Outputs) + + + Generating bulgarian language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\bulgarian.lng;%(Outputs) + + + Generating catalan language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\catalan.lng;%(Outputs) + + + Generating croatian language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\croatian.lng;%(Outputs) + + + Generating czech language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\czech.lng;%(Outputs) + + + Generating danish language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\danish.lng;%(Outputs) + + + Generating dutch language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\dutch.lng;%(Outputs) + + + Generating english_AU language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\english_AU.lng;%(Outputs) + + + Generating english_US language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\english_US.lng;%(Outputs) + + + Generating esperanto language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\esperanto.lng;%(Outputs) + + + Generating estonian language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\estonian.lng;%(Outputs) + + + Generating faroese language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\faroese.lng;%(Outputs) + + + Generating finnish language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\finnish.lng;%(Outputs) + + + Generating french language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\french.lng;%(Outputs) + + + Generating gaelic language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\gaelic.lng;%(Outputs) + + + Generating galician language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\galician.lng;%(Outputs) + + + Generating german language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\german.lng;%(Outputs) + + + Generating greek language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\greek.lng;%(Outputs) + + + Generating hebrew language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\hebrew.lng;%(Outputs) + + + Generating hungarian language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\hungarian.lng;%(Outputs) + + + Generating icelandic language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\icelandic.lng;%(Outputs) + + + Generating indonesian language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\indonesian.lng;%(Outputs) + + + Generating irish language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\irish.lng;%(Outputs) + + + Generating italian language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\italian.lng;%(Outputs) + + + Generating japanese language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\japanese.lng;%(Outputs) + + + Generating korean language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\korean.lng;%(Outputs) + + + Generating latin language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\latin.lng;%(Outputs) + + + Generating latvian language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\latvian.lng;%(Outputs) + + + Generating lithuanian language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\lithuanian.lng;%(Outputs) + + + Generating luxembourgish language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\luxembourgish.lng;%(Outputs) + + + Generating malay language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\malay.lng;%(Outputs) + + + Generating norwegian_bokmal language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\norwegian_bokmal.lng;%(Outputs) + + + Generating norwegian_nynorsk language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\norwegian_nynorsk.lng;%(Outputs) + + + Generating polish language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\polish.lng;%(Outputs) + + + Generating portuguese language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\portuguese.lng;%(Outputs) + + + Generating romanian language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\romanian.lng;%(Outputs) + + + Generating russian language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\russian.lng;%(Outputs) + + + Generating serbian language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\serbian.lng;%(Outputs) + + + Generating simplified_chinese language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\simplified_chinese.lng;%(Outputs) + + + Generating slovak language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\slovak.lng;%(Outputs) + + + Generating slovenian language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\slovenian.lng;%(Outputs) + + + Generating spanish language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\spanish.lng;%(Outputs) + + + Generating swedish language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\swedish.lng;%(Outputs) + + + Generating tamil language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\tamil.lng;%(Outputs) + + + Generating thai language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\thai.lng;%(Outputs) + + + Generating traditional_chinese language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\traditional_chinese.lng;%(Outputs) + + + Generating turkish language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\turkish.lng;%(Outputs) + + + Generating ukrainian language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\ukrainian.lng;%(Outputs) + + + Generating vietnamese language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\vietnamese.lng;%(Outputs) + + + Generating welsh language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\welsh.lng;%(Outputs) + + + + + {a133a442-bd0a-4ade-b117-ad7545e4bdd1} + false + + + + + + diff --git a/projects/langs_vs100.vcxproj.filters b/projects/langs_vs100.vcxproj.filters new file mode 100644 index 0000000..fb16aa6 --- /dev/null +++ b/projects/langs_vs100.vcxproj.filters @@ -0,0 +1,173 @@ + + + + + {2a164580-9033-4a01-974b-b21da507efda} + + + + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + Translations + + + diff --git a/projects/langs_vs100.vcxproj.filters.in b/projects/langs_vs100.vcxproj.filters.in new file mode 100644 index 0000000..0d60ee9 --- /dev/null +++ b/projects/langs_vs100.vcxproj.filters.in @@ -0,0 +1,12 @@ + + + + + {2a164580-9033-4a01-974b-b21da507efda} + + + + +!!FILES!! + + diff --git a/projects/langs_vs100.vcxproj.in b/projects/langs_vs100.vcxproj.in new file mode 100644 index 0000000..5bfec8b --- /dev/null +++ b/projects/langs_vs100.vcxproj.in @@ -0,0 +1,61 @@ + + + + + Debug + Win32 + + + + langs + {0F066B23-18DF-4284-8265-F4A5E7E3B966} + langs + MakeFileProj + + + + Utility + false + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\bin\lang\ + ..\objs\langs\ + + + + Generating strings.h + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\objs\langs\table + + + ./langs.tlb + + + + + + + Generating english language file + ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" + ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) + ..\bin\lang\english.lng;%(Outputs) + +!!FILES!! + + + + {a133a442-bd0a-4ade-b117-ad7545e4bdd1} + false + + + + + + diff --git a/projects/langs_vs80.vcproj b/projects/langs_vs80.vcproj new file mode 100644 index 0000000..1413a80 --- /dev/null +++ b/projects/langs_vs80.vcproj @@ -0,0 +1,880 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/langs_vs80.vcproj.in b/projects/langs_vs80.vcproj.in new file mode 100644 index 0000000..548a0b0 --- /dev/null +++ b/projects/langs_vs80.vcproj.in @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + +!!FILES!! + + + + + diff --git a/projects/langs_vs90.vcproj b/projects/langs_vs90.vcproj new file mode 100644 index 0000000..db6fef1 --- /dev/null +++ b/projects/langs_vs90.vcproj @@ -0,0 +1,881 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/langs_vs90.vcproj.in b/projects/langs_vs90.vcproj.in new file mode 100644 index 0000000..f03b231 --- /dev/null +++ b/projects/langs_vs90.vcproj.in @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + +!!FILES!! + + + + + diff --git a/projects/openttd_vs100.sln b/projects/openttd_vs100.sln new file mode 100644 index 0000000..a2ec939 --- /dev/null +++ b/projects/openttd_vs100.sln @@ -0,0 +1,91 @@ +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual C++ Express 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openttd", "openttd_vs100.vcxproj", "{668328A0-B40E-4CDB-BD72-D0064424414A}" + ProjectSection(ProjectDependencies) = postProject + {0817F629-589E-4A3B-B81A-8647BC571E35} = {0817F629-589E-4A3B-B81A-8647BC571E35} + {E9548DE9-F089-49B7-93A6-30BE2CC311C7} = {E9548DE9-F089-49B7-93A6-30BE2CC311C7} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "strgen", "strgen_vs100.vcxproj", "{A133A442-BD0A-4ADE-B117-AD7545E4BDD1}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "langs", "langs_vs100.vcxproj", "{0F066B23-18DF-4284-8265-F4A5E7E3B966}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "version", "version_vs100.vcxproj", "{1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "generate", "generate_vs100.vcxproj", "{2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "settings", "settings_vs100.vcxproj", "{0817F629-589E-4A3B-B81A-8647BC571E35}" + ProjectSection(ProjectDependencies) = postProject + {E9548DE9-F089-49B7-93A6-30BE2CC311C7} = {E9548DE9-F089-49B7-93A6-30BE2CC311C7} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "settingsgen", "settingsgen_vs100.vcxproj", "{E9548DE9-F089-49B7-93A6-30BE2CC311C7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|Win32.ActiveCfg = Debug|Win32 + {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|Win32.Build.0 = Debug|Win32 + {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|x64.ActiveCfg = Debug|x64 + {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|x64.Build.0 = Debug|x64 + {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|Win32.ActiveCfg = Release|Win32 + {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|Win32.Build.0 = Release|Win32 + {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|x64.ActiveCfg = Release|x64 + {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|x64.Build.0 = Release|x64 + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|Win32.ActiveCfg = Debug|Win32 + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|Win32.Build.0 = Debug|Win32 + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|x64.ActiveCfg = Debug|Win32 + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|x64.Build.0 = Debug|Win32 + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Release|Win32.ActiveCfg = Debug|Win32 + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Release|Win32.Build.0 = Debug|Win32 + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Release|x64.ActiveCfg = Debug|Win32 + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Release|x64.Build.0 = Debug|Win32 + {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Debug|Win32.ActiveCfg = Debug|Win32 + {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Debug|Win32.Build.0 = Debug|Win32 + {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Debug|x64.ActiveCfg = Debug|Win32 + {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Debug|x64.Build.0 = Debug|Win32 + {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Release|Win32.ActiveCfg = Debug|Win32 + {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Release|Win32.Build.0 = Debug|Win32 + {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Release|x64.ActiveCfg = Debug|Win32 + {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Release|x64.Build.0 = Debug|Win32 + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Debug|Win32.ActiveCfg = Debug|Win32 + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Debug|Win32.Build.0 = Debug|Win32 + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Debug|x64.ActiveCfg = Debug|Win32 + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Debug|x64.Build.0 = Debug|Win32 + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Release|Win32.ActiveCfg = Debug|Win32 + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Release|Win32.Build.0 = Debug|Win32 + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Release|x64.ActiveCfg = Debug|Win32 + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Release|x64.Build.0 = Debug|Win32 + {2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}.Debug|Win32.ActiveCfg = Debug|Win32 + {2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}.Debug|x64.ActiveCfg = Debug|Win32 + {2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}.Release|Win32.ActiveCfg = Debug|Win32 + {2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}.Release|x64.ActiveCfg = Debug|Win32 + {0817F629-589E-4A3B-B81A-8647BC571E35}.Debug|Win32.ActiveCfg = Debug|Win32 + {0817F629-589E-4A3B-B81A-8647BC571E35}.Debug|Win32.Build.0 = Debug|Win32 + {0817F629-589E-4A3B-B81A-8647BC571E35}.Debug|x64.ActiveCfg = Debug|Win32 + {0817F629-589E-4A3B-B81A-8647BC571E35}.Debug|x64.Build.0 = Debug|Win32 + {0817F629-589E-4A3B-B81A-8647BC571E35}.Release|Win32.ActiveCfg = Debug|Win32 + {0817F629-589E-4A3B-B81A-8647BC571E35}.Release|Win32.Build.0 = Debug|Win32 + {0817F629-589E-4A3B-B81A-8647BC571E35}.Release|x64.ActiveCfg = Debug|Win32 + {0817F629-589E-4A3B-B81A-8647BC571E35}.Release|x64.Build.0 = Debug|Win32 + {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Debug|Win32.ActiveCfg = Debug|Win32 + {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Debug|Win32.Build.0 = Debug|Win32 + {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Debug|x64.ActiveCfg = Debug|Win32 + {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Debug|x64.Build.0 = Debug|Win32 + {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Release|Win32.ActiveCfg = Debug|Win32 + {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Release|Win32.Build.0 = Debug|Win32 + {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Release|x64.ActiveCfg = Debug|Win32 + {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Release|x64.Build.0 = Debug|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(DPCodeReviewSolutionGUID) = preSolution + DPCodeReviewSolutionGUID = {00000000-0000-0000-0000-000000000000} + EndGlobalSection +EndGlobal diff --git a/projects/openttd_vs100.vcxproj b/projects/openttd_vs100.vcxproj new file mode 100644 index 0000000..aa8f3f6 --- /dev/null +++ b/projects/openttd_vs100.vcxproj @@ -0,0 +1,1303 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + openttd + {668328A0-B40E-4CDB-BD72-D0064424414A} + openttd + + + + Application + false + Unicode + + + Application + false + Unicode + true + + + Application + false + Unicode + + + Application + false + Unicode + true + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ + $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ + false + $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ + $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ + + $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ + false + $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ + $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ + $(ProjectDir)..\bin + + + + .\Release/openttd.tlb + + + + + /MP /J %(AdditionalOptions) + Full + AnySuitable + true + Size + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";%(PreprocessorDefinitions) + true + Sync + MultiThreaded + 4Bytes + false + true + + + + + + + All + $(IntDir) + $(IntDir) + $(IntDir)$(TargetName).pdb + Level3 + false + true + ProgramDatabase + FastCall + Default + + + NDEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies) + true + %(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + true + false + + + MachineX86 + true + + + + + .\Debug/openttd.tlb + + + + + /MP %(AdditionalOptions) + Disabled + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + $(IntDir) + $(IntDir) + $(IntDir)$(TargetName).pdb + Level3 + false + true + EditAndContinue + FastCall + Default + + + _DEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies) + true + LIBCMT.lib;%(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + false + + + MachineX86 + + + + + X64 + .\Release/openttd.tlb + + + + + /MP /J %(AdditionalOptions) + Full + AnySuitable + true + Size + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;%(PreprocessorDefinitions) + true + Sync + MultiThreaded + Default + false + true + + + + + + + All + $(IntDir) + $(IntDir) + $(IntDir)$(TargetName).pdb + Level3 + false + true + ProgramDatabase + FastCall + Default + + + NDEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies) + true + %(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + true + MachineX64 + true + + + + + X64 + .\Debug/openttd.tlb + + + + + /MP %(AdditionalOptions) + Disabled + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + + + + + $(IntDir) + $(IntDir) + $(IntDir)$(TargetName).pdb + Level3 + false + true + ProgramDatabase + Cdecl + Default + + + _DEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies) + true + LIBCMT.lib;%(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + MachineX64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {0f066b23-18df-4284-8265-f4a5e7e3b966} + false + + + {a133a442-bd0a-4ade-b117-ad7545e4bdd1} + false + + + {1a2b3c5e-1c23-41a5-9c9b-acba2aa75fec} + false + + + + diff --git a/projects/openttd_vs100.vcxproj.filters b/projects/openttd_vs100.vcxproj.filters new file mode 100644 index 0000000..08bdd98 --- /dev/null +++ b/projects/openttd_vs100.vcxproj.filters @@ -0,0 +1,3077 @@ + + + + + {c76ff9f1-1e62-46d8-8d55-000000000000} + + + {c76ff9f1-1e62-46d8-8d55-000000000001} + + + {c76ff9f1-1e62-46d8-8d55-000000000002} + + + {c76ff9f1-1e62-46d8-8d55-000000000003} + + + {c76ff9f1-1e62-46d8-8d55-000000000004} + + + {c76ff9f1-1e62-46d8-8d55-000000000005} + + + {c76ff9f1-1e62-46d8-8d55-000000000006} + + + {c76ff9f1-1e62-46d8-8d55-000000000007} + + + {c76ff9f1-1e62-46d8-8d55-000000000008} + + + {c76ff9f1-1e62-46d8-8d55-000000000009} + + + {c76ff9f1-1e62-46d8-8d55-000000000010} + + + {c76ff9f1-1e62-46d8-8d55-000000000011} + + + {c76ff9f1-1e62-46d8-8d55-000000000012} + + + {c76ff9f1-1e62-46d8-8d55-000000000013} + + + {c76ff9f1-1e62-46d8-8d55-000000000014} + + + {c76ff9f1-1e62-46d8-8d55-000000000015} + + + {c76ff9f1-1e62-46d8-8d55-000000000016} + + + {c76ff9f1-1e62-46d8-8d55-000000000017} + + + {c76ff9f1-1e62-46d8-8d55-000000000018} + + + {c76ff9f1-1e62-46d8-8d55-000000000019} + + + {c76ff9f1-1e62-46d8-8d55-000000000020} + + + {c76ff9f1-1e62-46d8-8d55-000000000021} + + + {c76ff9f1-1e62-46d8-8d55-000000000022} + + + {c76ff9f1-1e62-46d8-8d55-000000000023} + + + {c76ff9f1-1e62-46d8-8d55-000000000024} + + + {c76ff9f1-1e62-46d8-8d55-000000000025} + + + {c76ff9f1-1e62-46d8-8d55-000000000026} + + + {c76ff9f1-1e62-46d8-8d55-000000000027} + + + {c76ff9f1-1e62-46d8-8d55-000000000028} + + + {c76ff9f1-1e62-46d8-8d55-000000000029} + + + {c76ff9f1-1e62-46d8-8d55-000000000030} + + + {c76ff9f1-1e62-46d8-8d55-000000000031} + + + {c76ff9f1-1e62-46d8-8d55-000000000032} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + Core Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + GUI Source Code + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Widgets + + + Command handlers + + + Command handlers + + + Command handlers + + + Command handlers + + + Command handlers + + + Command handlers + + + Command handlers + + + Command handlers + + + Command handlers + + + Command handlers + + + Command handlers + + + Command handlers + + + Command handlers + + + Command handlers + + + Command handlers + + + Command handlers + + + Command handlers + + + Command handlers + + + Command handlers + + + Command handlers + + + Command handlers + + + Command handlers + + + Command handlers + + + Command handlers + + + Command handlers + + + Command handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Save/Load handlers + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + Tables + + + MD5 + + + MD5 + + + Script + + + Script + + + Script + + + Script + + + Script + + + Script + + + Script + + + Script + + + Script + + + Script + + + Script + + + Script + + + Script + + + Script + + + Script + + + Script + + + Script + + + Script + + + Script + + + Squirrel + + + Squirrel + + + Squirrel + + + Squirrel + + + Squirrel + + + Squirrel + + + Squirrel + + + Squirrel + + + Squirrel + + + Squirrel + + + Squirrel + + + Squirrel + + + Squirrel + + + Squirrel + + + Squirrel headers + + + Squirrel headers + + + Squirrel headers + + + Squirrel headers + + + Squirrel headers + + + Squirrel headers + + + Squirrel headers + + + Squirrel headers + + + Squirrel headers + + + Squirrel headers + + + Squirrel headers + + + Squirrel headers + + + Squirrel headers + + + Squirrel headers + + + Squirrel headers + + + Squirrel headers + + + Squirrel headers + + + Squirrel headers + + + Squirrel headers + + + Squirrel headers + + + AI Core + + + AI Core + + + AI Core + + + AI Core + + + AI Core + + + AI Core + + + AI Core + + + AI Core + + + AI Core + + + AI Core + + + AI Core + + + AI Core + + + AI API + + + Game API + + + Game Core + + + Game Core + + + Game Core + + + Game Core + + + Game Core + + + Game Core + + + Game Core + + + Game Core + + + Game Core + + + Game Core + + + Game Core + + + Game Core + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Script API Implementation + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Blitters + + + Drivers + + + Drivers + + + Drivers + + + Sprite loaders + + + Sprite loaders + + + Sprite loaders + + + NewGRF + + + NewGRF + + + NewGRF + + + NewGRF + + + NewGRF + + + NewGRF + + + NewGRF + + + NewGRF + + + NewGRF + + + NewGRF + + + NewGRF + + + NewGRF + + + NewGRF + + + NewGRF + + + NewGRF + + + NewGRF + + + NewGRF + + + NewGRF + + + NewGRF + + + NewGRF + + + NewGRF + + + Map Accessors + + + Map Accessors + + + Map Accessors + + + Map Accessors + + + Map Accessors + + + Map Accessors + + + Map Accessors + + + Map Accessors + + + Map Accessors + + + Map Accessors + + + Map Accessors + + + Map Accessors + + + Map Accessors + + + Map Accessors + + + Map Accessors + + + Map Accessors + + + Map Accessors + + + Misc + + + Misc + + + Misc + + + Misc + + + Misc + + + Misc + + + Misc + + + Misc + + + Misc + + + Misc + + + Misc + + + Misc + + + Network Core + + + Network Core + + + Network Core + + + Network Core + + + Network Core + + + Network Core + + + Network Core + + + Network Core + + + Network Core + + + Network Core + + + Network Core + + + Network Core + + + Network Core + + + Network Core + + + Network Core + + + Network Core + + + Network Core + + + Network Core + + + Network Core + + + Network Core + + + Network Core + + + Network Core + + + Network Core + + + Network Core + + + Network Core + + + Pathfinder + + + Pathfinder + + + Pathfinder + + + Pathfinder + + + Pathfinder + + + Pathfinder + + + NPF + + + NPF + + + NPF + + + NPF + + + NPF + + + NPF + + + YAPF + + + YAPF + + + YAPF + + + YAPF + + + YAPF + + + YAPF + + + YAPF + + + YAPF + + + YAPF + + + YAPF + + + YAPF + + + YAPF + + + YAPF + + + YAPF + + + YAPF + + + YAPF + + + YAPF + + + YAPF + + + Video + + + Video + + + Video + + + Video + + + Music + + + Music + + + Music + + + Sound + + + Sound + + + Sound + + + Windows files + + + Windows files + + + Windows files + + + Threading + + + Threading + + + + + + + diff --git a/projects/openttd_vs100.vcxproj.filters.in b/projects/openttd_vs100.vcxproj.filters.in new file mode 100644 index 0000000..cda4910 --- /dev/null +++ b/projects/openttd_vs100.vcxproj.filters.in @@ -0,0 +1,13 @@ + + + +!!FILTERS!! + + +!!FILES!! + + + + + + diff --git a/projects/openttd_vs100.vcxproj.in b/projects/openttd_vs100.vcxproj.in new file mode 100644 index 0000000..51703af --- /dev/null +++ b/projects/openttd_vs100.vcxproj.in @@ -0,0 +1,315 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + openttd + {668328A0-B40E-4CDB-BD72-D0064424414A} + openttd + + + + Application + false + Unicode + + + Application + false + Unicode + true + + + Application + false + Unicode + + + Application + false + Unicode + true + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ + $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ + false + $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ + $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ + + $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ + false + $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ + $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ + $(ProjectDir)..\bin + + + + .\Release/openttd.tlb + + + + + /MP /J %(AdditionalOptions) + Full + AnySuitable + true + Size + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";%(PreprocessorDefinitions) + true + Sync + MultiThreaded + 4Bytes + false + true + + + + + + + All + $(IntDir) + $(IntDir) + $(IntDir)$(TargetName).pdb + Level3 + false + true + ProgramDatabase + FastCall + Default + + + NDEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies) + true + %(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + true + false + + + MachineX86 + true + + + + + .\Debug/openttd.tlb + + + + + /MP %(AdditionalOptions) + Disabled + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + $(IntDir) + $(IntDir) + $(IntDir)$(TargetName).pdb + Level3 + false + true + EditAndContinue + FastCall + Default + + + _DEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies) + true + LIBCMT.lib;%(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + false + + + MachineX86 + + + + + X64 + .\Release/openttd.tlb + + + + + /MP /J %(AdditionalOptions) + Full + AnySuitable + true + Size + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;%(PreprocessorDefinitions) + true + Sync + MultiThreaded + Default + false + true + + + + + + + All + $(IntDir) + $(IntDir) + $(IntDir)$(TargetName).pdb + Level3 + false + true + ProgramDatabase + FastCall + Default + + + NDEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies) + true + %(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + true + MachineX64 + true + + + + + X64 + .\Debug/openttd.tlb + + + + + /MP %(AdditionalOptions) + Disabled + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + + + + + $(IntDir) + $(IntDir) + $(IntDir)$(TargetName).pdb + Level3 + false + true + ProgramDatabase + Cdecl + Default + + + _DEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies) + true + LIBCMT.lib;%(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + MachineX64 + + + +!!FILES!! + + + + + + + + {0f066b23-18df-4284-8265-f4a5e7e3b966} + false + + + {a133a442-bd0a-4ade-b117-ad7545e4bdd1} + false + + + {1a2b3c5e-1c23-41a5-9c9b-acba2aa75fec} + false + + + + diff --git a/projects/openttd_vs80.sln b/projects/openttd_vs80.sln new file mode 100644 index 0000000..9e6dd12 --- /dev/null +++ b/projects/openttd_vs80.sln @@ -0,0 +1,95 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual C++ Express 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openttd", "openttd_vs80.vcproj", "{668328A0-B40E-4CDB-BD72-D0064424414A}" + ProjectSection(ProjectDependencies) = postProject + {0F066B23-18DF-4284-8265-F4A5E7E3B966} = {0F066B23-18DF-4284-8265-F4A5E7E3B966} + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC} = {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC} + {0817F629-589E-4A3B-B81A-8647BC571E35} = {0817F629-589E-4A3B-B81A-8647BC571E35} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "strgen", "strgen_vs80.vcproj", "{A133A442-BD0A-4ADE-B117-AD7545E4BDD1}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "langs", "langs_vs80.vcproj", "{0F066B23-18DF-4284-8265-F4A5E7E3B966}" + ProjectSection(ProjectDependencies) = postProject + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1} = {A133A442-BD0A-4ADE-B117-AD7545E4BDD1} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "version", "version_vs80.vcproj", "{1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "generate", "generate_vs80.vcproj", "{2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "settings", "settings_vs80.vcproj", "{0817F629-589E-4A3B-B81A-8647BC571E35}" + ProjectSection(ProjectDependencies) = postProject + {E9548DE9-F089-49B7-93A6-30BE2CC311C7} = {E9548DE9-F089-49B7-93A6-30BE2CC311C7} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "settings_gen", "settingsgen_vs80.vcproj", "{E9548DE9-F089-49B7-93A6-30BE2CC311C7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|Win32.ActiveCfg = Debug|Win32 + {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|Win32.Build.0 = Debug|Win32 + {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|x64.ActiveCfg = Debug|x64 + {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|x64.Build.0 = Debug|x64 + {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|Win32.ActiveCfg = Release|Win32 + {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|Win32.Build.0 = Release|Win32 + {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|x64.ActiveCfg = Release|x64 + {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|x64.Build.0 = Release|x64 + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|Win32.ActiveCfg = Debug|Win32 + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|Win32.Build.0 = Debug|Win32 + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|x64.ActiveCfg = Debug|Win32 + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|x64.Build.0 = Debug|Win32 + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Release|Win32.ActiveCfg = Debug|Win32 + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Release|Win32.Build.0 = Debug|Win32 + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Release|x64.ActiveCfg = Debug|Win32 + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Release|x64.Build.0 = Debug|Win32 + {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Debug|Win32.ActiveCfg = Debug|Win32 + {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Debug|Win32.Build.0 = Debug|Win32 + {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Debug|x64.ActiveCfg = Debug|Win32 + {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Debug|x64.Build.0 = Debug|Win32 + {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Release|Win32.ActiveCfg = Debug|Win32 + {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Release|Win32.Build.0 = Debug|Win32 + {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Release|x64.ActiveCfg = Debug|Win32 + {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Release|x64.Build.0 = Debug|Win32 + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Debug|Win32.ActiveCfg = Debug|Win32 + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Debug|Win32.Build.0 = Debug|Win32 + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Debug|x64.ActiveCfg = Debug|Win32 + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Debug|x64.Build.0 = Debug|Win32 + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Release|Win32.ActiveCfg = Debug|Win32 + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Release|Win32.Build.0 = Debug|Win32 + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Release|x64.ActiveCfg = Debug|Win32 + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Release|x64.Build.0 = Debug|Win32 + {2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}.Debug|Win32.ActiveCfg = Debug|Win32 + {2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}.Debug|x64.ActiveCfg = Debug|Win32 + {2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}.Release|Win32.ActiveCfg = Debug|Win32 + {2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}.Release|x64.ActiveCfg = Debug|Win32 + {0817F629-589E-4A3B-B81A-8647BC571E35}.Debug|Win32.ActiveCfg = Debug|Win32 + {0817F629-589E-4A3B-B81A-8647BC571E35}.Debug|Win32.Build.0 = Debug|Win32 + {0817F629-589E-4A3B-B81A-8647BC571E35}.Debug|x64.ActiveCfg = Debug|Win32 + {0817F629-589E-4A3B-B81A-8647BC571E35}.Debug|x64.Build.0 = Debug|Win32 + {0817F629-589E-4A3B-B81A-8647BC571E35}.Release|Win32.ActiveCfg = Debug|Win32 + {0817F629-589E-4A3B-B81A-8647BC571E35}.Release|Win32.Build.0 = Debug|Win32 + {0817F629-589E-4A3B-B81A-8647BC571E35}.Release|x64.ActiveCfg = Debug|Win32 + {0817F629-589E-4A3B-B81A-8647BC571E35}.Release|x64.Build.0 = Debug|Win32 + {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Debug|Win32.ActiveCfg = Debug|Win32 + {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Debug|Win32.Build.0 = Debug|Win32 + {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Debug|x64.ActiveCfg = Debug|Win32 + {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Debug|x64.Build.0 = Debug|Win32 + {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Release|Win32.ActiveCfg = Debug|Win32 + {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Release|Win32.Build.0 = Debug|Win32 + {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Release|x64.ActiveCfg = Debug|Win32 + {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Release|x64.Build.0 = Debug|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(DPCodeReviewSolutionGUID) = preSolution + DPCodeReviewSolutionGUID = {00000000-0000-0000-0000-000000000000} + EndGlobalSection +EndGlobal diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj new file mode 100644 index 0000000..a70ebce --- /dev/null +++ b/projects/openttd_vs80.vcproj @@ -0,0 +1,4533 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/openttd_vs80.vcproj.in b/projects/openttd_vs80.vcproj.in new file mode 100644 index 0000000..8992c9d --- /dev/null +++ b/projects/openttd_vs80.vcproj.in @@ -0,0 +1,446 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +!!FILES!! + + + + + + + + diff --git a/projects/openttd_vs80.vcproj.user b/projects/openttd_vs80.vcproj.user new file mode 100644 index 0000000..2d523a7 --- /dev/null +++ b/projects/openttd_vs80.vcproj.user @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + diff --git a/projects/openttd_vs90.sln b/projects/openttd_vs90.sln new file mode 100644 index 0000000..a33f315 --- /dev/null +++ b/projects/openttd_vs90.sln @@ -0,0 +1,95 @@ +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual C++ Express 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openttd", "openttd_vs90.vcproj", "{668328A0-B40E-4CDB-BD72-D0064424414A}" + ProjectSection(ProjectDependencies) = postProject + {0F066B23-18DF-4284-8265-F4A5E7E3B966} = {0F066B23-18DF-4284-8265-F4A5E7E3B966} + {0817F629-589E-4A3B-B81A-8647BC571E35} = {0817F629-589E-4A3B-B81A-8647BC571E35} + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC} = {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "strgen", "strgen_vs90.vcproj", "{A133A442-BD0A-4ADE-B117-AD7545E4BDD1}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "langs", "langs_vs90.vcproj", "{0F066B23-18DF-4284-8265-F4A5E7E3B966}" + ProjectSection(ProjectDependencies) = postProject + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1} = {A133A442-BD0A-4ADE-B117-AD7545E4BDD1} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "version", "version_vs90.vcproj", "{1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "generate", "generate_vs90.vcproj", "{2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "settings", "settings_vs90.vcproj", "{0817F629-589E-4A3B-B81A-8647BC571E35}" + ProjectSection(ProjectDependencies) = postProject + {E9548DE9-F089-49B7-93A6-30BE2CC311C7} = {E9548DE9-F089-49B7-93A6-30BE2CC311C7} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "settingsgen", "settingsgen_vs90.vcproj", "{E9548DE9-F089-49B7-93A6-30BE2CC311C7}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|Win32.ActiveCfg = Debug|Win32 + {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|Win32.Build.0 = Debug|Win32 + {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|x64.ActiveCfg = Debug|x64 + {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|x64.Build.0 = Debug|x64 + {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|Win32.ActiveCfg = Release|Win32 + {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|Win32.Build.0 = Release|Win32 + {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|x64.ActiveCfg = Release|x64 + {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|x64.Build.0 = Release|x64 + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|Win32.ActiveCfg = Debug|Win32 + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|Win32.Build.0 = Debug|Win32 + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|x64.ActiveCfg = Debug|Win32 + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|x64.Build.0 = Debug|Win32 + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Release|Win32.ActiveCfg = Debug|Win32 + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Release|Win32.Build.0 = Debug|Win32 + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Release|x64.ActiveCfg = Debug|Win32 + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Release|x64.Build.0 = Debug|Win32 + {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Debug|Win32.ActiveCfg = Debug|Win32 + {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Debug|Win32.Build.0 = Debug|Win32 + {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Debug|x64.ActiveCfg = Debug|Win32 + {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Debug|x64.Build.0 = Debug|Win32 + {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Release|Win32.ActiveCfg = Debug|Win32 + {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Release|Win32.Build.0 = Debug|Win32 + {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Release|x64.ActiveCfg = Debug|Win32 + {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Release|x64.Build.0 = Debug|Win32 + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Debug|Win32.ActiveCfg = Debug|Win32 + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Debug|Win32.Build.0 = Debug|Win32 + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Debug|x64.ActiveCfg = Debug|Win32 + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Debug|x64.Build.0 = Debug|Win32 + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Release|Win32.ActiveCfg = Debug|Win32 + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Release|Win32.Build.0 = Debug|Win32 + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Release|x64.ActiveCfg = Debug|Win32 + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Release|x64.Build.0 = Debug|Win32 + {2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}.Debug|Win32.ActiveCfg = Debug|Win32 + {2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}.Debug|x64.ActiveCfg = Debug|Win32 + {2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}.Release|Win32.ActiveCfg = Debug|Win32 + {2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}.Release|x64.ActiveCfg = Debug|Win32 + {0817F629-589E-4A3B-B81A-8647BC571E35}.Debug|Win32.ActiveCfg = Debug|Win32 + {0817F629-589E-4A3B-B81A-8647BC571E35}.Debug|Win32.Build.0 = Debug|Win32 + {0817F629-589E-4A3B-B81A-8647BC571E35}.Debug|x64.ActiveCfg = Debug|Win32 + {0817F629-589E-4A3B-B81A-8647BC571E35}.Debug|x64.Build.0 = Debug|Win32 + {0817F629-589E-4A3B-B81A-8647BC571E35}.Release|Win32.ActiveCfg = Debug|Win32 + {0817F629-589E-4A3B-B81A-8647BC571E35}.Release|Win32.Build.0 = Debug|Win32 + {0817F629-589E-4A3B-B81A-8647BC571E35}.Release|x64.ActiveCfg = Debug|Win32 + {0817F629-589E-4A3B-B81A-8647BC571E35}.Release|x64.Build.0 = Debug|Win32 + {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Debug|Win32.ActiveCfg = Debug|Win32 + {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Debug|Win32.Build.0 = Debug|Win32 + {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Debug|x64.ActiveCfg = Debug|Win32 + {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Debug|x64.Build.0 = Debug|Win32 + {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Release|Win32.ActiveCfg = Debug|Win32 + {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Release|Win32.Build.0 = Debug|Win32 + {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Release|x64.ActiveCfg = Debug|Win32 + {E9548DE9-F089-49B7-93A6-30BE2CC311C7}.Release|x64.Build.0 = Debug|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(DPCodeReviewSolutionGUID) = preSolution + DPCodeReviewSolutionGUID = {00000000-0000-0000-0000-000000000000} + EndGlobalSection +EndGlobal diff --git a/projects/openttd_vs90.vcproj b/projects/openttd_vs90.vcproj new file mode 100644 index 0000000..06c5312 --- /dev/null +++ b/projects/openttd_vs90.vcproj @@ -0,0 +1,4530 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/openttd_vs90.vcproj.in b/projects/openttd_vs90.vcproj.in new file mode 100644 index 0000000..56fa1c0 --- /dev/null +++ b/projects/openttd_vs90.vcproj.in @@ -0,0 +1,443 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +!!FILES!! + + + + + + + + diff --git a/projects/openttd_vs90.vcproj.user b/projects/openttd_vs90.vcproj.user new file mode 100644 index 0000000..b49492a --- /dev/null +++ b/projects/openttd_vs90.vcproj.user @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + diff --git a/projects/settings_vs100.vcxproj b/projects/settings_vs100.vcxproj new file mode 100644 index 0000000..b6684d3 --- /dev/null +++ b/projects/settings_vs100.vcxproj @@ -0,0 +1,54 @@ +ï»??xml version="1.0" encoding="utf-8"?> + + + + Debug + Win32 + + + + settings + {0817F629-589E-4A3B-B81A-8647BC571E35} + settings + + + + Makefile + + + + + + + + + +..\objs\settings\settings_gen.exe -o ..\objs\settings\table\settings.h -b ..\src\table\settings.h.preamble -a ..\src\table\settings.h.postamble ..\src\table\company_settings.ini ..\src\table\currency_settings.ini ..\src\table\gameopt_settings.ini ..\src\table\misc_settings.ini ..\src\table\settings.ini ..\src\table\win32_settings.ini ..\src\table\window_settings.ini + + + + <_ProjectFileVersion>10.0.30319.1 + ..\objs\settings\table\ + ..\objs\settings\table\ + $(SettingsCommandLine) + $(SettingsCommandLine) + del ..\objs\settings\table\settings.h + ..\objs\settings\table\settings.h + + + + + + + + + + + + + + + + + + diff --git a/projects/settings_vs100.vcxproj.filters b/projects/settings_vs100.vcxproj.filters new file mode 100644 index 0000000..62bf11b --- /dev/null +++ b/projects/settings_vs100.vcxproj.filters @@ -0,0 +1,35 @@ +ï»??xml version="1.0" encoding="utf-8"?> + + + + {21deca6c-8df4-4f34-9dad-17d7781cd5a0} + + + + + INI + + + INI + + + INI + + + INI + + + INI + + + INI + + + INI + + + + + + + diff --git a/projects/settings_vs100.vcxproj.filters.in b/projects/settings_vs100.vcxproj.filters.in new file mode 100644 index 0000000..08f9067 --- /dev/null +++ b/projects/settings_vs100.vcxproj.filters.in @@ -0,0 +1,15 @@ + + + + + {21deca6c-8df4-4f34-9dad-17d7781cd5a0} + + + +!!FILES!! + + + + + + diff --git a/projects/settings_vs100.vcxproj.in b/projects/settings_vs100.vcxproj.in new file mode 100644 index 0000000..46064b5 --- /dev/null +++ b/projects/settings_vs100.vcxproj.in @@ -0,0 +1,48 @@ + + + + + Debug + Win32 + + + + settings + {0817F629-589E-4A3B-B81A-8647BC571E35} + settings + + + + Makefile + + + + + + + + + +!!FILTERS!! + + + + <_ProjectFileVersion>10.0.30319.1 + ..\objs\settings\table\ + ..\objs\settings\table\ + $(SettingsCommandLine) + $(SettingsCommandLine) + del ..\objs\settings\table\settings.h + ..\objs\settings\table\settings.h + + +!!FILES!! + + + + + + + + + diff --git a/projects/settings_vs80.vcproj b/projects/settings_vs80.vcproj new file mode 100644 index 0000000..0084dcb --- /dev/null +++ b/projects/settings_vs80.vcproj @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/settings_vs80.vcproj.in b/projects/settings_vs80.vcproj.in new file mode 100644 index 0000000..a0f10fb --- /dev/null +++ b/projects/settings_vs80.vcproj.in @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + +!!FILES!! + + + + + + + + + diff --git a/projects/settings_vs90.vcproj b/projects/settings_vs90.vcproj new file mode 100644 index 0000000..4361e8d --- /dev/null +++ b/projects/settings_vs90.vcproj @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/settings_vs90.vcproj.in b/projects/settings_vs90.vcproj.in new file mode 100644 index 0000000..a342e2b --- /dev/null +++ b/projects/settings_vs90.vcproj.in @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + +!!FILES!! + + + + + + + + + diff --git a/projects/settingsgen_vs100.vcxproj b/projects/settingsgen_vs100.vcxproj new file mode 100644 index 0000000..cbf8df0 --- /dev/null +++ b/projects/settingsgen_vs100.vcxproj @@ -0,0 +1,81 @@ + + + + + Debug + Win32 + + + + settingsgen + {E9548DE9-F089-49B7-93A6-30BE2CC311C7} + settings + + + + Application + MultiByte + v140 + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\objs\settings\ + ..\objs\settings\ + settings_gen + + + + + + + + %(Inputs) + + + MinSpace + Size + SETTINGSGEN;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + All + $(IntDir)$(TargetName).pdb + Level3 + ProgramDatabase + MultiThreadedDebug + + + $(OutDir)settings_gen.exe + true + false + + + Console + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/projects/settingsgen_vs100.vcxproj.filters b/projects/settingsgen_vs100.vcxproj.filters new file mode 100644 index 0000000..c8afe0c --- /dev/null +++ b/projects/settingsgen_vs100.vcxproj.filters @@ -0,0 +1,32 @@ + + + + + {a4678737-b3b3-4be5-9db1-fa6ccd164c59} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + + + + + + diff --git a/projects/settingsgen_vs80.vcproj b/projects/settingsgen_vs80.vcproj new file mode 100644 index 0000000..7568ce9 --- /dev/null +++ b/projects/settingsgen_vs80.vcproj @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/settingsgen_vs90.vcproj b/projects/settingsgen_vs90.vcproj new file mode 100644 index 0000000..015ddd2 --- /dev/null +++ b/projects/settingsgen_vs90.vcproj @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/strgen_vs100.vcxproj b/projects/strgen_vs100.vcxproj new file mode 100644 index 0000000..d7c7b82 --- /dev/null +++ b/projects/strgen_vs100.vcxproj @@ -0,0 +1,94 @@ + + + + + Debug + Win32 + + + + strgen + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1} + strgen + + + + Application + false + MultiByte + v140 + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)..\objs\strgen\ + $(SolutionDir)..\objs\strgen\ + false + AllRules.ruleset + + + + + + .\Debug/strgen.tlb + + + + + /MP %(AdditionalOptions) + MinSpace + Size + STRGEN;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + Default + MultiThreadedDebug + + + All + $(IntDir) + $(IntDir) + $(IntDir)$(TargetName).pdb + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x041d + + + true + true + $(IntDir)strgen.pdb + Console + false + + + MachineX86 + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/projects/strgen_vs100.vcxproj.filters b/projects/strgen_vs100.vcxproj.filters new file mode 100644 index 0000000..58864ee --- /dev/null +++ b/projects/strgen_vs100.vcxproj.filters @@ -0,0 +1,35 @@ + + + + + {5894294c-d4dc-41f0-be31-e56cff4e0405} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + + + + + + + + diff --git a/projects/strgen_vs80.vcproj b/projects/strgen_vs80.vcproj new file mode 100644 index 0000000..4450279 --- /dev/null +++ b/projects/strgen_vs80.vcproj @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/strgen_vs90.vcproj b/projects/strgen_vs90.vcproj new file mode 100644 index 0000000..ca194e0 --- /dev/null +++ b/projects/strgen_vs90.vcproj @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/version_vs100.vcxproj b/projects/version_vs100.vcxproj new file mode 100644 index 0000000..008e6dd --- /dev/null +++ b/projects/version_vs100.vcxproj @@ -0,0 +1,42 @@ + + + + + Debug + Win32 + + + + version + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC} + version + + + + Makefile + MultiByte + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)..\objs\version\ + $(SolutionDir)..\objs\version\ + cscript "$(ProjectDir)/determineversion.vbs" + cscript "$(ProjectDir)/determineversion.vbs" + ..\src\rev.cpp + del ..\src\rev.cpp + + + + + + + + + \ No newline at end of file diff --git a/projects/version_vs80.vcproj b/projects/version_vs80.vcproj new file mode 100644 index 0000000..4b1660b --- /dev/null +++ b/projects/version_vs80.vcproj @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/version_vs90.vcproj b/projects/version_vs90.vcproj new file mode 100644 index 0000000..3c3d58a --- /dev/null +++ b/projects/version_vs90.vcproj @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..c2f8ce6 --- /dev/null +++ b/readme.txt @@ -0,0 +1,734 @@ +Last updated: 2015-12-01 +Release version: 1.5.3 +------------------------------------------------------------------------ + + +Table of contents +----------------- +1.0) About +2.0) Contacting + * 2.1) Reporting bugs + * 2.2) Reporting desyncs +3.0) Supported platforms +4.0) Installing and running OpenTTD + * 4.1) (Required) 3rd party files + * 4.2) OpenTTD directories + * 4.3) Portable installations (portable media) + * 4.4) Files in tar (archives) +5.0) OpenTTD features + * 5.1) Logging of potentially dangerous actions +6.0) Configuration file +7.0) Compiling + * 7.1) Required/optional libraries + * 7.2) Supported compilers + * 7.3) Compilation of base sets +8.0) Translating + * 8.1) Translation + * 8.2) Previewing +9.0) Troubleshooting +10.0) Licensing +X.X) Credits + + +1.0) About +---- ----- +OpenTTD is a transport simulation game based upon the popular game Transport +Tycoon Deluxe, written by Chris Sawyer. It attempts to mimic the original +game as closely as possible while extending it with new features. + +OpenTTD is licensed under the GNU General Public License version 2.0, +but includes some 3rd party software under different licenses. See the +section "Licensing" below for details. + +2.0) Contacting +---- ---------- +The easiest way to contact the OpenTTD team is by submitting bug reports or +posting comments in our forums. You can also chat with us on IRC (#openttd +on irc.oftc.net). + +The OpenTTD homepage is http://www.openttd.org/. + +You can also find the OpenTTD forums at +http://forum.openttd.org/ + +2.1) Reporting bugs +---- -------------- +First of all, check whether the bug is not already known. Do this by looking +through the file called 'known-bugs.txt' which is distributed with OpenTTD +like this readme. + +For tracking our bugs we are using a bug tracker called Flyspray. You can find +the tracker at http://bugs.openttd.org/. Before actually reporting take a look +through the already reported bugs there to see if the bug is already known. +The 'known-bugs.txt' file might be a bit outdated at the moment you are +reading it as only bugs known before the release are documented there. Also +look through the recently closed bugs. + +When you are sure it is not already reported you should: + * Make sure you are running a recent version, i.e. run the latest stable or + nightly based on where you found the bug. + * Make sure you are not running a non-official binary, like a patch pack. + When you are playing with a patch pack you should report any bugs to the + forum thread related to that patch pack. + * Make it reproducible for the developers. In other words, create a savegame + in which you can reproduce the issue once loaded. It is very useful to give + us the crash.dmp, crash.sav, crash.log and crash screenshot which are + created on crashes. + * Check whether the bug is already reported on our bug tracker. This includes + searching for recently closed bug reports as the bug might already be fixed. + +After you have done all that you can report the bug. Please include the +following information in your bug report: + * OpenTTD version (PLEASE test the latest SVN/nightly build) + * Bug details, including instructions how to reproduce it + * Platform (Windows, Linux, FreeBSD, ...) and compiler (including version) if + you compiled OpenTTD yourself. + * The processor architecture of your OS (32 bits Windows, 64 bits Windows, + Linux on an ARM, Mac OS X on a PowerPC, ...) + * Attach a saved game *and* a screenshot if possible + * If this bug only occurred recently please note the last version without + the bug and the first version including the bug. That way we can fix it + quicker by looking at the changes made. + * Attach crash.dmp, crash.log and crash.sav. These files are usually created + next to your openttd.cfg. The crash handler will tell you the location. + +2.2) Reporting desyncs +---- ----------------- +As desyncs are hard to make reproducible OpenTTD has the ability to log all +actions done by clients so we can replay the whole game in an effort to make +desyncs better reproducible. You need to turn this ability on. When turned +on an automatic savegame will be made once the map has been constructed in +the 'save/autosave' directory, see OpenTTD directories to know where to find +this directory. Furthermore the log file 'commands-out.log' will be created +and all actions will be written to there. + +To enable the desync debugging you need to set the debug level for 'desync' +to at least 1. You do this by starting OpenTTD with '-d desync=' as +parameter or by typing 'debug_level desync=' in OpenTTD's internal +console. +The desync debug levels are: + 0: nothing. + 1: dumping of commands to 'commands-out.log'. + 2: same as 1 plus checking vehicle caches and dumping that too. + 3: same as 2 plus monthly saves in autosave. + 4 and higher: same as 3 + +Restarting OpenTTD will overwrite 'commands-out.log'. OpenTTD will not remove +the savegames (dmp_cmds_*.sav) made by the desync debugging system, so you +have to occasionally remove them yourself! + +The naming format of the desync savegames is as follows: +dmp_cmds_XXXXXXXX_YYYYYYYY.sav. The XXXXXXXX is the hexadecimal representation +of the generation seed of the game and YYYYYYYY is the hexadecimal +representation of the date of the game. This sorts the savegames by game and +then by date making it easier to find the right savegames. + +When a desync has occurred with the desync debugging turned on you should file +a bug report with the following files attached: + - commands-out.log as it contains all the commands that were done + - the last saved savegame (search for the last line beginning with + 'save: dmp_cmds_' in commands-out.log). We use this savegame to check + whether we can quickly reproduce the desync. Otherwise we will need... + - the first saved savegame (search for the first line beginning with 'save' + where the first part, up to the last underscore '_', is the same). We need + this savegame to be able to reproduce the bug when the last savegame is not + old enough. If you loaded a scenario or savegame you need to attach that. + - optionally you can attach the savegames from around 50%, 75%, 85%, 90% and + 95% of the game's progression. We can use these savegames to speed up the + reproduction of the desync, but we should be able to reproduce these + savegames based on the first savegame and commands-out.log. + - in case you use any NewGRFs you should attach the ones you used unless + we can easily find them ourselves via bananas or when they are in the + #openttdcoop pack. + +Do NOT remove the dmp_cmds savegames of a desync you have reported until the +desync has been fixed; if you, by accident, send us the wrong savegames we +will not be able to reproduce the desync and thus will be unable to fix it. + + +3.0) Supported platforms +---- ------------------- +OpenTTD has been ported to several platforms and operating systems. It should +not be very difficult to port it to a new platform. The currently working +platforms are: + + BeOS - SDL or Allegro + DOS - Allegro + FreeBSD - SDL + Linux - SDL or Allegro + MacOS X (universal) - Cocoa video and sound drivers + MorphOS - SDL + OpenBSD - SDL + OS/2 - SDL + Windows - Win32 GDI (faster) or SDL or Allegro + + +4.0) Installing and running OpenTTD +---- ------------------------------ +Installing OpenTTD is fairly straightforward. Either you have downloaded an +archive which you have to extract to a directory where you want OpenTTD to +be installed, or you have downloaded an installer, which will automatically +extract OpenTTD in the given directory. + +OpenTTD looks in multiple locations to find the required data files (described +in section 4.2). Installing any 3rd party files into a 'shared' location has +the advantage that you only need to do this step once, rather than copying the +data files into all OpenTTD versions you have. +Savegames, screenshots, etc are saved relative to the config file (openttd.cfg) +currently being used. This means that if you use a config file in one of the +shared directories, savegames will reside in the save/ directory next to the +openttd.cfg file there. +If you want savegames and screenshots in the directory where the OpenTTD binary +resides, simply have your config file in that location. But if you remove this +config file, savegames will still be in this directory (see notes in +section 4.2 'OpenTTD directories') + +OpenTTD comes without AIs, so if you want to play with AIs you have to download +them. The easiest way is via the 'Check Online Content' button in the main menu. +You can select some AIs that you think are compatible with your playing style. +Another way is manually downloading the AIs from the forum although then you +need to make sure that you install all the required AI libraries too; they get +automatically selected (and downloaded) if you get the AIs via the 'Check +Online Content'. If you do not have an AI but have configured OpenTTD to start +an AI a message will be shown that the 'dummy' AI has been started. + +4.1) (Required) 3rd party files +---- -------------------------- +Before you run OpenTTD, you need to put the game's data files into a baseset/ +directory which can be located in various places addressed in the following +section. + +For OpenTTD you need to acquire some third party data files. For this you have +the choice of using the original Transport Tycoon Deluxe data files or a set +of free data files. + +Do NOT copy files included with OpenTTD into 'shared' directories (explained in +the following sections) as sooner or later you will run into graphical glitches +when using other versions of the game. + +4.1.1) Free graphics and sound files +------ ----------------------------- +The free data files, split into OpenGFX for graphics, OpenSFX for sounds and +OpenMSX for music can be found at: + - http://www.openttd.org/download-opengfx for OpenGFX + - http://www.openttd.org/download-opensfx for OpenSFX + - http://www.openttd.org/download-openmsx for OpenMSX +Please follow the readme of these packages about the installation procedure. +The Windows installer can optionally download and install these packages. + +4.1.2) Original Transport Tycoon Deluxe graphics and sound files +------ --------------------------------------------------------- +If you want to play with the original Transport Tycoon Deluxe data files you +have to copy the data files from the CD-ROM into the baseset/ directory. It +does not matter whether you copy them from the DOS or Windows version of +Transport Tycoon Deluxe. The Windows install can optionally copy these files. +You need to copy the following files: + - sample.cat + - trg1r.grf or TRG1.GRF + - trgcr.grf or TRGC.GRF + - trghr.grf or TRGH.GRF + - trgir.grf or TRGI.GRF + - trgtr.grf or TRGT.GRF + +4.1.3) Original Transport Tycoon Deluxe music +------ -------------------------------------- +If you want the Transport Tycoon Deluxe music, copy the files from the gm/ +folder from the Windows version of Transport Tycoon Deluxe to the baseset +folder in your OpenTTD folder (also explained in the following sections). +The music from the DOS version as well as the original Transport Tycoon does +not work. + +4.1.4) AIs +------ --- +If you want AIs use the in-game content downloader. If for some reason that is +not possible or you want to use an AI that has not been uploaded to the content +download system download the tar file and place it in the ai/ directory. If the +AI needs libraries you will have to download those too and put them in the +ai/library/ directory. All AIs and AI Libraries that have been uploaded to +the content download system can be found at http://noai.openttd.org/downloads/ +The AIs and libraries can be found their in the form of .tar.gz packages. +OpenTTD can read inside tar files but it does not extract .tar.gz files by +itself. +To figure out which libraries you need for an AI you have to start the AI and +wait for an error message to pop up. The error message will tell you +'could not find library "lib-name"'. Download that library and try again. + +4.1.5) Game scripts +------ ------------ +If you want an extra challenge in OpenTTD you can download so-called game +scripts via the in-game content downloader. These game scripts have varying +functionality, though they can generally influence town growth, subsidies, add +goals to reach or provide a different ranking system. +If you download a game script manually you have to follow the same rules as for +AIs, except that game scripts are placed in the game/ directory instead of the +ai/ directory. + + +4.2) OpenTTD directories +---- ------------------- +OpenTTD uses its own directory to store its required 3rd party base set files +(see section 4.1 'Required 3rd party files') and non-compulsory extension and +configuration files. See below for their proper place within this OpenTTD main +data directory. + +The main OpenTTD directories can be found in various locations, depending on +your operating system: + 1. The current working directory (from where you started OpenTTD) + For non-Windows operating systems OpenTTD will not scan for files in this + directory if it is your personal directory, i.e. '~/', or when it is the + root directory, i.e. '/'. + 2. Your personal directory + Windows: C:\My Documents\OpenTTD (95, 98, ME) + C:\Documents and Settings\\My Documents\OpenTTD (2000, XP) + C:\Users\\Documents\OpenTTD (Vista, 7) + Mac OSX: ~/Documents/OpenTTD + Linux: $XDG_DATA_HOME/openttd which is usually ~/.local/share/openttd when + built with XDG base directory support, otherwise ~/.openttd + 3. The shared directory + Windows: C:\Documents and Settings\All Users\Shared Documents\OpenTTD (2000, XP) + C:\Users\Public\Documents\OpenTTD (Vista, 7) + Mac OSX: /Library/Application Support/OpenTTD + Linux: not available + 4. The binary directory (where the OpenTTD executable is) + Windows: C:\Program Files\OpenTTD + Linux: /usr/games + 5. The installation directory (Linux only) + Linux: /usr/share/games/openttd + 6. The application bundle (Mac OSX only) + It includes the OpenTTD files (grf+lng) and it will work as long as they + are not touched + +Different types of data or extensions go into different subdirectories of the +chosen main OpenTTD directory: + Config File: (no subdirectory) + Screenshots: screenshot + Base Graphics: baseset (or a subdirectory thereof) + Sound Sets: baseset (or a subdirectory thereof) + NewGRFs: newgrf (or a subdirectory thereof) + 32bpp Sets: newgrf (or a subdirectory thereof) + Music Sets: baseset (or a subdirectory thereof) + AIs: ai (or a subdirectory thereof) + AI Libraries: ai/libraries (or a subdirectory thereof) + Game Scripts (GS): game (or a subdirectory thereof) + GS Libraries: game/libraries (or a subdirectory thereof) + Savegames: save + Automatic Savegames: save/autosave + Scenarios: scenario + +The (automatically created) directory content_download is for OpenTTD's internal +use and no files should be added to it or its subdirectories manually. + +Notes: + - Linux in the previous list means .deb, but most paths should be similar for + others. + - The previous search order is also used for NewGRFs and openttd.cfg. + - If openttd.cfg is not found, then it will be created using the 2, 4, 1, 3, + 5 order. When built with XDG base directory support, openttd.cfg will be + created in $XDG_CONFIG_HOME/openttd which is usually ~/.config/openttd. + - Savegames will be relative to the config file only if there is no save/ + directory in paths with higher priority than the config file path, but + autosaves and screenshots will always be relative to the config file. + Unless the configuration file is in $XDG_CONFIG_HOME/openttd, then all + other files will be saved under $XDG_DATA_HOME/openttd. + +The preferred setup: +Place 3rd party files in shared directory (or in personal directory if you do +not have write access on shared directory) and have your openttd.cfg config +file in personal directory (where the game will then also place savegames and +screenshots). + +4.3) Portable installations (portable media) +---- --------------------------------------- +You can install OpenTTD on external media so you can take it with you, i.e. +using a USB key, or a USB HDD, etc. +Create a directory where you shall store the game in (i.e. OpenTTD/). +Copy the binary (OpenTTD.exe, OpenTTD.app, openttd, etc), baseset/ and your +openttd.cfg to this directory. +You can copy binaries for any operating system into this directory, which will +allow you to play the game on nearly any computer you can attach the external +media to. +As always - additional grf files are stored in the newgrf/ dir (for details, +again, see section 4.1). + +4.4) Files in tar (archives) +---- ----------------------- +OpenTTD can read files that are in an uncompressed tar (archive), which +makes it easy to bundle files belonging to the same script, NewGRF or base +set. Music sets are the only exception as they cannot be stored in a tar +file due to being played by external applications. + +OpenTTD sees each tar archive as the 'root' of its search path. This means that +having a file with the same path in two different tar files means that one +cannot be opened, after all only one file will be found first. As such it is +advisable to put an uniquely named folder in the root of the tar and put all the +content in that folder. For example, all downloaded content has a path that +concatenates the name of the content and the version, which makes the path +unique. For custom tar files it is advised to do this as well. + +The normal files are also referred to by their relative path from the search +directory, this means that also normal files could hide files in a tar as +long as the relative path from the search path of the normal file is the +same as the path in the tar file. Again it is advised to have an unique path +to the normal file so they do not collide with the files from other tar +files. + + +5.0) OpenTTD features +---- ---------------- +OpenTTD has a lot of features going beyond the original Transport Tycoon Deluxe +emulation. Unfortunately, there is currently no comprehensive list of features, +but there is a basic features list on the web, and some optional features can be +controlled through the Advanced Settings dialog. We also implement some +features known from TTDPatch (http://www.ttdpatch.net/). + +Several important non-standard controls: + +* Ctrl modifies many commands and makes them more powerful. For example Ctrl + clicking on signals with the build signal tool changes their behaviour, holding + Ctrl while the track build tool is activated changes it to the track removal + tool, and so on. See http://wiki.openttd.org/Hidden_features for a non- + comprehensive list or look at the tooltips. +* Ingame console. More information at + http://wiki.openttd.org/index.php/Console +* Hovering over a GUI element shows tooltips. This can be changed to right click + via the advanced settings. + +5.1) Logging of potentially dangerous actions +---- ---------------------------------------- +OpenTTD is a complex program, and together with NewGRF, it may show a buggy +behaviour. But not only bugs in code can cause problems. There are several +ways to affect game state possibly resulting in program crash or multiplayer +desyncs. +Easier way would be to forbid all these unsafe actions, but that would affect +game usability for many players. We certainly do not want that. +However, we receive bug reports because of this. To reduce time spent with +solving these problems, these potentially unsafe actions are logged in +the savegame (including crash.sav). Log is stored in crash logs, too. + +Information logged: + +* Adding / removing / changing order of NewGRFs +* Changing NewGRF parameters, loading compatible NewGRF +* Changing game mode (scenario editor <-> normal game) +* Loading game saved in a different OpenTTD / TTDPatch / Transport Tycoon Deluxe / + original Transport Tycoon version +* Running a modified OpenTTD build +* Changing settings affecting NewGRF behaviour (non-network-safe settings) +* Triggering NewGRF bugs + +No personal information is stored. + +You can show the game log by typing 'gamelog' in the console or by running +OpenTTD in debug mode. + + +6.0) Configuration file +---- ------------------ +The configuration file for OpenTTD (openttd.cfg) is in a simple Windows-like +.INI format. It is mostly undocumented. Almost all settings can be changed +ingame by using the 'Advanced Settings' window. +When you cannot find openttd.cfg you should look in the directories as +described in section 4.2. If you do not have an openttd.cfg OpenTTD will +create one after closing. + + +7.0) Compiling +---- --------- +Windows: + You need Microsoft Visual Studio .NET. Open the project file + and it should build automatically. In case you want to build with SDL support + you need to add WITH_SDL to the project settings. + PNG (WITH_PNG) and ZLIB (WITH_ZLIB) support is enabled by default. For these + to work you need their development files. For best results, download the + openttd-useful.zip file from http://www.openttd.org/download-openttd-useful + Put the header files into your compiler's include/ directory and the + library (.lib) files into the lib/ directory. + For more help with VS see docs/Readme_Windows_MSVC.txt. + + You can also build it using the Makefile with MSYS/MinGW or Cygwin/MinGW. + Please read the Makefile for more information. + +Solaris, FreeBSD, OpenBSD: + Use 'gmake', but do a './configure' before the first build. + +Linux/Unix: + OpenTTD can be built with GNU 'make'. On non-GNU systems it is called 'gmake'. + However, for the first build one has to do a './configure' first. + +MacOS X: + Use 'make' or Xcode (which will then call make for you) + This will give you a binary for your CPU type (PPC/Intel) + However, for the first build one has to do a './configure' first. + To make a universal binary type './configure --enabled-universal' + instead of './configure'. + +BeOS: + Use 'make', but do a './configure' before the first build. + +MorphOS: + Use 'make'. However, for the first build one has to do a './configure' first. + Note that you need the MorphOS SDK, latest libnix updates (else C++ parts of + OpenTTD will not build) and the powersdl.library SDK. Optionally libz, + libpng and freetype2 developer files. + +OS/2: + A comprehensive GNU build environment is required to build the OS/2 version. + See the docs/Readme_OS2.txt file for more information. + +DOS: + A build environment with DJGPP is needed as well as libraries such as + Allegro, zlib and libpng, which all can be downloaded from the DJGPP + website. Compilation is straight forward: use make, but do a './configure' + before the first build. The build binary will need cwsdpmi.exe to be in + the same directory as the openttd executable. cwsdpmi.exe can be found in + the os/dos/cwsdpmi subdirectory. If you compile with stripping turned on a + binary will be generated that does not need cwsdpmi.exe by adding the + cswdstub.exe to the created OpenTTD binary. + +7.1) Required/optional libraries +---- --------------------------- +The following libraries are used by OpenTTD for: + - libSDL/liballegro: hardware access (video, sound, mouse) + - zlib: (de)compressing of old (0.3.0-1.0.5) savegames, content downloads, + heightmaps + - liblzo2: (de)compressing of old (pre 0.3.0) savegames + - liblzma: (de)compressing of savegames (1.1.0 and later) + - libpng: making screenshots and loading heightmaps + - libfreetype: loading generic fonts and rendering them + - libfontconfig: searching for fonts, resolving font names to actual fonts + - libicu: handling of right-to-left scripts (e.g. Arabic and Persian) and + natural sorting of strings. + +OpenTTD does not require any of the libraries to be present, but without +liblzma you cannot open most recent savegames and without zlib you cannot +open most older savegames or use the content downloading system. +Without libSDL/liballegro on non-Windows and non-MacOS X machines you have +no graphical user interface; you would be building a dedicated server. + +7.2) Supported compilers +---- ------------------- +The following compilers are known to compile OpenTTD: + - Microsoft Visual C++ (MSVC) 2005, 2008 and 2010. + Version 2005 gives bogus warnings about scoping issues. + - GNU Compiler Collection (GCC) 3.3 - 4.4, 4.6 - 4.8. + Versions 4.1 and earlier give bogus warnings about uninitialised variables. + Versions 4.4, 4.6 give bogus warnings about freeing non-heap objects. + Versions 4.6 and later give invalid warnings when lto is enabled. + - Intel C++ Compiler (ICC) 12.0. + - Clang/LLVM 2.9 - 3.0 + Version 2.9 gives bogus warnings about code nonconformity. + +The following compilers are known not to compile OpenTTD: + - Microsoft Visual C++ (MSVC) 2003 and earlier. + - GNU Compiler Collection (GCC) 3.2 and earlier. + These old versions fail due to OpenTTD's template usage. + - GNU Compiler Collection (GCC) 4.5. It optimizes enums too aggressively. + See http://bugs.openttd.org/task/5513 and references therein. + - Intel C++ Compiler (ICC) 11.1 and earlier. + Version 10.0 and earlier fail a configure check and fail with recent system + headers. + Version 10.1 fails to compile station_gui.cpp. + Version 11.1 fails with an internal error when compiling network.cpp. + - Clang/LLVM 2.8 and earlier. + - (Open) Watcom. + +If any of these compilers can compile OpenTTD again, please let us know. +Patches to support more compilers are welcome. + +7.3) Compilation of base sets +----------------------------- +To recompile the extra graphics needed to play with the original Transport +Tycoon Deluxe graphics you need GRFCodec (which includes NFORenum) as well. +GRFCodec can be found at: http://www.openttd.org/download-grfcodec +The compilation of these extra graphics does generally not happen, unless +you remove the graphics file using 'make maintainer-clean'. + +Re-compilation of the base sets, thus also use of --maintainer-clean can +leave the repository in a modified state as different grfcodec versions can +cause binary differences in the resulting grf. Also translations might have +been added for the base sets which are not yet included in the base set +information files. Use the configure option --without-grfcodec to avoid +modification of the base set files by the build process. + + +8.0) Translating +---- ----------- +See http://www.openttd.org/development for up-to-date information. + +The use of the online Translator service, located at +http://translator.openttd.org/, is highly encouraged. For getting an account +simply follow the guidelines in the FAQ of the translator website. + +If for some reason the website is down for a longer period of time, the +information below might be of help. + +Please contact the translations manager (http://www.openttd.org/contact) +before beginning the translation process! This avoids double work, as +someone else may have already started translating to the same language. + +8.1) Translation +---- ----------- +So, now that you have notified the development team about your intention to +translate (You did, right? Of course you did.) you can pick up english.txt +(found in the SVN repository under /src/lang) and translate. + +You must change the first two lines of the file appropriately: + +##name English-Name-Of-Language +##ownname Native-Name-Of-Language + +Note: Do not alter the following parts of the file: + + * String identifiers (the first word on each line) + * Parts of the strings which are in curly braces (such as {STRING}) + * Lines beginning with ## (such as ##id), other than the first two lines of + the file + +8.2) Previewing +---- ---------- +In order to view the translation in the game, you need to compile your language +file with the strgen utility. As this utility is tailored to a specific OpenTTD +version, you need to compile it yourself. Just take the normal OpenTTD sources +and build that. During the build process the strgen utility will be made. + +strgen is a command-line utility. It takes the language filename as parameter. +Example: + +strgen lang/german.txt + +This results in compiling german.txt and produces another file named german.lng. +Any missing strings are replaced with the English strings. Note that it looks +for english.txt in the lang subdirectory, which is where your language file +should also be. + +That is all! You should now be able to select the language in the game options. + + +9.0) Troubleshooting +---- --------------- +To see all startup options available to you, start OpenTTD with the +'./openttd -h' option. This might help you tweak some of the settings. + +If the game is acting strange and you feel adventurous you can try the +'-d [[=]]' flag, where the higher levels will give you more +debugging output. The 'name' variable can help you to display only some type of +debugging messages. This is mostly undocumented so best is to look in the +source code file debug.c for the various debugging types. For more information +look at http://wiki.openttd.org/index.php/Command_line. + +The most frequent problem is missing data files. Please install OpenGFX and +possibly OpenSFX and OpenMSX. See section 4.1.1 for more information. + +Under certain circumstance, especially on Ubuntu OpenTTD can be extremely slow +and/or freeze. See known-bugs.txt for more information and how to solve this +problem on your computer. + +Under Windows 98 and lower it is impossible to use a dedicated server; it will +fail to start. Perhaps this is for the better because those OSes are not known +for their stability. + +With the added support for font-based text selecting a non-latin language can +result in lots of question marks ('?') being shown on screen. Please open your +configuration file (openttd.cfg - see Section 4.2 for where to find it) +and add a suitable font for the small, medium and / or large font, e.g.: + small_font = "Tahoma" + medium_font = "Tahoma" + large_font = "Tahoma" +You should use a font name like 'Tahoma' or a path to the desired font. + +Any NewGRF file used in a game is stored inside the savegame and will refuse +to load if you do not have that NewGRF file available. A list of missing files +can be viewed in the NewGRF window accessible from the file load dialogue window. + +You can try to obtain the missing files from that NewGRF dialogue or - if they +are not available online - you can search manually through our forum's graphics +development section (http://www.tt-forums.net/viewforum.php?f=66) or GrfCrawler +(http://grfcrawler.tt-forums.net/). Put the NewGRF files in OpenTTD's newgrf folder +(see section 4.2 'OpenTTD directories') and rescan the list of available NewGRFs. +Once you have all missing files, you are set to go. + +10.0) Licensing +----- --------- +OpenTTD is licensed under the GNU General Public License version 2.0. For +the complete license text, see the file 'COPYING'. This license applies +to all files in this distribution, except as noted below. + +The squirrel implementation in src/3rdparty/squirrel is licensed under +the Zlib license. See src/3rdparty/squirrel/COPYRIGHT for the complete +license text. + +The md5 implementation in src/3rdparty/md5 is licensed under the Zlib +license. See the comments in the source files in src/3rdparty/md5 for +the complete license text. + +The implementations of Posix getaddrinfo and getnameinfo for OS/2 in +src/3rdparty/os2 are distributed partly under the GNU Lesser General Public +License 2.1, and partly under the (3-clause) BSD license. The exact licensing +terms can be found in src/3rdparty/os2/getaddrinfo.c resp. +src/3rdparty/os2/getnameinfo.c. + +The exe2coff implementation in os/dos/exe2coff is available under the +GPL, with a number of additional terms. See os/dos/exe2coff/copying and +os/dos/exe2coff/copying.dj for the exact licensing terms. + +The CWSDPMI implementation in os/dos/cwsdpmi is distributed under a +custom binary-only license that prohibits modification. The exact +licensing terms can be found in os/dos/cwsdpmi/cwsdpmi.txt. The sources +for these files can be downloaded at its author site, at: +http://homer.rice.edu/~sandmann/cwsdpmi/csdpmi5s.zip + +X.X) Credits +---- ------- +The OpenTTD team (in alphabetical order): + Albert Hofkamp (Alberth) - GUI expert (since 0.7) + Matthijs Kooijman (blathijs) - Pathfinder-guru, Debian port (since 0.3) + Ulf Hermann (fonsinchen) - Cargo Distribution (since 1.3) + Christoph Elsenhans (frosch) - General coding (since 0.6) + Loïc Guilloux (glx) - Windows Expert (since 0.4.5) + Michael Lutz (michi_cc) - Path based signals (since 0.7) + Owen Rudge (orudge) - Forum host, OS/2 port (since 0.1) + Peter Nelson (peter1138) - Spiritual descendant from newGRF gods (since 0.4.5) + Ingo von Borstel (planetmaker) - General coding, Support (since 1.1) + Remko Bijker (Rubidium) - Lead coder and way more (since 0.4.5) + José Soler (Terkhen) - General coding (since 1.0) + Leif Linse (Zuu) - AI/Game Script (since 1.2) + +Inactive Developers: + Jean-François Claeys (Belugas) - GUI, newindustries and more (0.4.5 - 1.0) + Bjarni Corfitzen (Bjarni) - MacOSX port, coder and vehicles (0.3 - 0.7) + Victor Fischer (Celestar) - Programming everywhere you need him to (0.3 - 0.6) + Jaroslav Mazanec (KUDr) - YAPG (Yet Another Pathfinder God) ;) (0.4.5 - 0.6) + Jonathan Coome (Maedhros) - High priest of the NewGRF Temple (0.5 - 0.6) + Attila Bán (MiHaMiX) - WebTranslator 1 and 2 (0.3 - 0.5) + ZdenÄ›k Sojka (SmatZ) - Bug finder and fixer (0.6 - 1.3) + Christoph Mallon (Tron) - Programmer, code correctness police (0.3 - 0.5) + Patric Stout (TrueBrain) - NoProgrammer (0.3 - 1.2), sys op (active) + Thijs Marinussen (Yexo) - AI Framework, General (0.6 - 1.3) + +Retired Developers: + Tamás Faragó (Darkvater) - Ex-Lead coder (0.3 - 0.5) + Dominik Scherer (dominik81) - Lead programmer, GUI expert (0.3 - 0.3) + Emil Djupfeld (egladil) - MacOSX port (0.4 - 0.6) + Simon Sasburg (HackyKid) - Bug fixer (0.4 - 0.4.5) + Ludvig Strigeus (ludde) - Original author of OpenTTD, main coder (0.1 - 0.3) + Cian Duffy (MYOB) - BeOS port / manual writing (0.1 - 0.3) + Petr BaudiÅ¡ (pasky) - Many patches, newgrf support, etc. (0.3 - 0.3) + Benedikt Brüggemeier (skidd13) - Bug fixer and code reworker (0.6 - 0.7) + Serge Paquet (vurlix) - 2nd contributor after ludde (0.1 - 0.3) + +Thanks to: + Josef Drexler - For his great work on TTDPatch. + Marcin Grzegorczyk - For his TTDPatch work and documentation of Transport Tycoon Deluxe internals and track foundations + Stefan Meißner (sign_de) - For his work on the console + Mike Ragsdale - OpenTTD installer + Christian Rosentreter (tokai) - MorphOS / AmigaOS port + Richard Kempton (RichK67) - Additional airports, initial TGP implementation + Alberto Demichelis - Squirrel scripting language + L. Peter Deutsch - MD5 implementation + Michael Blunck - For revolutionizing TTD with awesome graphics + George - Canal graphics + Andrew Parkhouse (andythenorth) - River graphics + David Dallaston (Pikka) - Tram tracks + All Translators - For their support to make OpenTTD a truly international game + Bug Reporters - Thanks for all bug reports + Chris Sawyer - For an amazing game! diff --git a/source.list b/source.list new file mode 100644 index 0000000..cdadecd --- /dev/null +++ b/source.list @@ -0,0 +1,1204 @@ +# Source Files +airport.cpp +animated_tile.cpp +articulated_vehicles.cpp +autoreplace.cpp +bmp.cpp +cargoaction.cpp +cargomonitor.cpp +cargopacket.cpp +cargotype.cpp +cheat.cpp +command.cpp +console.cpp +console_cmds.cpp +cpu.cpp +crashlog.cpp +currency.cpp +date.cpp +debug.cpp +dedicated.cpp +departures.cpp +depot.cpp +disaster_vehicle.cpp +driver.cpp +economy.cpp +effectvehicle.cpp +elrail.cpp +engine.cpp +fileio.cpp +fios.cpp +fontcache.cpp +fontdetection.cpp +base_consist.cpp +gamelog.cpp +genworld.cpp +gfx.cpp +gfxinit.cpp +gfx_layout.cpp +goal.cpp +ground_vehicle.cpp +heightmap.cpp +highscore.cpp +hotkeys.cpp +infrastructure.cpp +ini.cpp +ini_load.cpp +landscape.cpp +linkgraph/demands.cpp +linkgraph/flowmapper.cpp +linkgraph/linkgraph.cpp +linkgraph/linkgraphjob.cpp +linkgraph/linkgraphschedule.cpp +linkgraph/mcf.cpp +linkgraph/refresh.cpp +map.cpp +misc.cpp +mixer.cpp +music.cpp +network/network.cpp +network/network_admin.cpp +network/network_client.cpp +network/network_command.cpp +network/network_content.cpp +network/network_gamelist.cpp +network/network_server.cpp +network/network_udp.cpp +openttd.cpp +order_backup.cpp +pbs.cpp +progress.cpp +rail.cpp +rev.cpp +road.cpp +roadstop.cpp +screenshot.cpp +#if SDL + sdl.cpp +#end +settings.cpp +signal.cpp +signs.cpp +sound.cpp +sprite.cpp +spritecache.cpp +station.cpp +strgen/strgen_base.cpp +string.cpp +stringfilter.cpp +strings.cpp +story.cpp +subsidy.cpp +textbuf.cpp +texteff.cpp +tgp.cpp +tile_map.cpp +tilearea.cpp +townname.cpp +#if WIN32 +#else + #if WINCE + #else + #if OS2 + os/os2/os2.cpp + 3rdparty/os2/getaddrinfo.c + 3rdparty/os2/getaddrinfo.h + 3rdparty/os2/getnameinfo.c + 3rdparty/os2/getnameinfo.h + #else + #if OSX + os/macosx/crashlog_osx.cpp + #else + os/unix/crashlog_unix.cpp + #end + os/unix/unix.cpp + #end + #end +#end +vehicle.cpp +vehiclelist.cpp +viewport.cpp +#if SSE +viewport_sprite_sorter_sse4.cpp +#end +waypoint.cpp +widget.cpp +window.cpp + +# Header Files +#if ALLEGRO + music/allegro_m.h + sound/allegro_s.h + video/allegro_v.h +#end +aircraft.h +airport.h +animated_tile_func.h +articulated_vehicles.h +autoreplace_base.h +autoreplace_func.h +autoreplace_gui.h +autoreplace_type.h +autoslope.h +base_media_base.h +base_media_func.h +base_station_base.h +bmp.h +bridge.h +cargo_type.h +cargoaction.h +cargomonitor.h +cargopacket.h +cargotype.h +cheat_func.h +cheat_type.h +clear_func.h +cmd_helper.h +command_func.h +command_type.h +company_base.h +company_func.h +company_gui.h +company_manager_face.h +company_type.h +console_func.h +console_gui.h +console_internal.h +console_type.h +cpu.h +crashlog.h +currency.h +date_func.h +date_gui.h +date_type.h +debug.h +video/dedicated_v.h +departures_func.h +departures_gui.h +departures_type.h +depot_base.h +depot_func.h +depot_map.h +depot_type.h +direction_func.h +direction_type.h +disaster_vehicle.h +music/dmusic.h +driver.h +economy_base.h +economy_func.h +economy_type.h +effectvehicle_base.h +effectvehicle_func.h +elrail_func.h +engine_base.h +engine_func.h +engine_gui.h +engine_type.h +error.h +fileio_func.h +fileio_type.h +fios.h +fontcache.h +fontdetection.h +base_consist.h +gamelog.h +gamelog_internal.h +genworld.h +gfx_func.h +gfx_layout.h +gfx_type.h +gfxinit.h +goal_base.h +goal_type.h +graph_gui.h +ground_vehicle.hpp +group.h +group_gui.h +group_type.h +gui.h +heightmap.h +highscore.h +hotkeys.h +house.h +house_type.h +industry.h +industry_type.h +industrytype.h +infrastructure_func.h +ini_type.h +landscape.h +landscape_type.h +language.h +linkgraph/demands.h +linkgraph/flowmapper.h +linkgraph/init.h +linkgraph/linkgraph.h +linkgraph/linkgraph_base.h +linkgraph/linkgraph_gui.h +linkgraph/linkgraph_type.h +linkgraph/linkgraphjob.h +linkgraph/linkgraphjob_base.h +linkgraph/linkgraphschedule.h +linkgraph/mcf.h +linkgraph/refresh.h +livery.h +map_func.h +map_type.h +mixer.h +network/network.h +network/network_admin.h +network/network_base.h +network/network_client.h +network/network_content.h +network/network_content_gui.h +network/network_func.h +network/network_gamelist.h +network/network_gui.h +network/network_internal.h +network/network_server.h +network/network_type.h +network/network_udp.h +newgrf.h +newgrf_airport.h +newgrf_airporttiles.h +newgrf_animation_base.h +newgrf_animation_type.h +newgrf_callbacks.h +newgrf_canal.h +newgrf_cargo.h +newgrf_class.h +newgrf_class_func.h +newgrf_commons.h +newgrf_config.h +newgrf_debug.h +newgrf_engine.h +newgrf_generic.h +newgrf_house.h +newgrf_industries.h +newgrf_industrytiles.h +newgrf_object.h +newgrf_properties.h +newgrf_railtype.h +newgrf_sound.h +newgrf_spritegroup.h +newgrf_station.h +newgrf_storage.h +newgrf_text.h +newgrf_town.h +newgrf_townname.h +news_func.h +news_gui.h +news_type.h +music/null_m.h +sound/null_s.h +video/null_v.h +object.h +object_base.h +object_type.h +openttd.h +order_backup.h +order_base.h +order_func.h +order_type.h +pbs.h +progress.h +querystring_gui.h +rail.h +rail_gui.h +rail_type.h +rev.h +road_cmd.h +road_func.h +road_gui.h +road_internal.h +road_type.h +roadstop_base.h +roadveh.h +safeguards.h +screenshot.h +sdl.h +sound/sdl_s.h +video/sdl_v.h +settings_func.h +settings_gui.h +settings_internal.h +settings_type.h +ship.h +signal_func.h +signal_type.h +signs_base.h +signs_func.h +signs_type.h +slope_func.h +slope_type.h +smallmap_gui.h +sortlist_type.h +sound_func.h +sound_type.h +sprite.h +spritecache.h +station_base.h +station_func.h +station_gui.h +station_type.h +statusbar_gui.h +stdafx.h +story_base.h +story_type.h +strgen/strgen.h +string_base.h +string_func.h +string_type.h +stringfilter_type.h +strings_func.h +strings_type.h +subsidy_base.h +subsidy_func.h +subsidy_type.h +tar_type.h +terraform_gui.h +textbuf_gui.h +textbuf_type.h +texteff.hpp +textfile_gui.h +textfile_type.h +tgp.h +tile_cmd.h +tile_type.h +tilearea_type.h +tilehighlight_func.h +tilehighlight_type.h +tilematrix_type.hpp +timetable.h +toolbar_gui.h +town.h +town_type.h +townname_func.h +townname_type.h +track_func.h +track_type.h +train.h +transparency.h +transparency_gui.h +transport_type.h +tunnelbridge.h +vehicle_base.h +vehicle_func.h +vehicle_gui.h +vehicle_gui_base.h +vehicle_type.h +vehiclelist.h +viewport_func.h +viewport_sprite_sorter.h +viewport_type.h +watch_gui.h +water.h +waypoint_base.h +waypoint_func.h +widget_type.h +os/windows/win32.h +music/win32_m.h +sound/win32_s.h +video/win32_v.h +window_func.h +window_gui.h +window_type.h +zoom_func.h +zoom_type.h +#if WIN32 +#else +music/bemidi.h +music/cocoa_m.h +music/extmidi.h +music/libtimidity.h +music/os2_m.h +music/qtmidi.h +os/macosx/macos.h +os/macosx/osx_stdafx.h +os/macosx/splash.h +sound/cocoa_s.h +video/cocoa/cocoa_keys.h +video/cocoa/cocoa_v.h +#end + +# Core Source Code +core/alloc_func.cpp +core/alloc_func.hpp +core/alloc_type.hpp +core/backup_type.hpp +core/bitmath_func.cpp +core/bitmath_func.hpp +core/endian_func.hpp +core/endian_type.hpp +core/enum_type.hpp +core/geometry_func.cpp +core/geometry_func.hpp +core/geometry_type.hpp +core/math_func.cpp +core/math_func.hpp +core/mem_func.hpp +core/multimap.hpp +core/overflowsafe_type.hpp +core/pool_func.cpp +core/pool_func.hpp +core/pool_type.hpp +core/random_func.cpp +core/random_func.hpp +core/smallmap_type.hpp +core/smallmatrix_type.hpp +core/smallstack_type.hpp +core/smallvec_type.hpp +core/sort_func.hpp +core/string_compare_type.hpp + +# GUI Source Code +aircraft_gui.cpp +airport_gui.cpp +autoreplace_gui.cpp +bootstrap_gui.cpp +bridge_gui.cpp +build_vehicle_gui.cpp +cheat_gui.cpp +company_gui.cpp +console_gui.cpp +date_gui.cpp +departures_gui.cpp +depot_gui.cpp +dock_gui.cpp +engine_gui.cpp +error_gui.cpp +fios_gui.cpp +genworld_gui.cpp +goal_gui.cpp +graph_gui.cpp +group_gui.cpp +highscore_gui.cpp +industry_gui.cpp +intro_gui.cpp +linkgraph/linkgraph_gui.cpp +main_gui.cpp +misc_gui.cpp +music_gui.cpp +network/network_chat_gui.cpp +network/network_content_gui.cpp +network/network_gui.cpp +newgrf_debug_gui.cpp +newgrf_gui.cpp +news_gui.cpp +object_gui.cpp +order_gui.cpp +osk_gui.cpp +rail_gui.cpp +road_gui.cpp +roadveh_gui.cpp +settings_gui.cpp +ship_gui.cpp +signs_gui.cpp +smallmap_gui.cpp +station_gui.cpp +statusbar_gui.cpp +story_gui.cpp +subsidy_gui.cpp +terraform_gui.cpp +textfile_gui.cpp +timetable_gui.cpp +toolbar_gui.cpp +town_gui.cpp +train_gui.cpp +transparency_gui.cpp +tree_gui.cpp +vehicle_gui.cpp +viewport_gui.cpp +watch_gui.cpp +waypoint_gui.cpp + +# Widgets +widgets/airport_widget.h +widgets/ai_widget.h +widgets/autoreplace_widget.h +widgets/bootstrap_widget.h +widgets/bridge_widget.h +widgets/build_vehicle_widget.h +widgets/cheat_widget.h +widgets/company_widget.h +widgets/console_widget.h +widgets/date_widget.h +widgets/departures_widget.h +widgets/depot_widget.h +widgets/dock_widget.h +widgets/dropdown.cpp +widgets/dropdown_func.h +widgets/dropdown_type.h +widgets/dropdown_widget.h +widgets/engine_widget.h +widgets/error_widget.h +widgets/fios_widget.h +widgets/genworld_widget.h +widgets/goal_widget.h +widgets/graph_widget.h +widgets/group_widget.h +widgets/highscore_widget.h +widgets/industry_widget.h +widgets/intro_widget.h +widgets/link_graph_legend_widget.h +widgets/main_widget.h +widgets/misc_widget.h +widgets/music_widget.h +widgets/network_chat_widget.h +widgets/network_content_widget.h +widgets/network_widget.h +widgets/newgrf_debug_widget.h +widgets/newgrf_widget.h +widgets/news_widget.h +widgets/object_widget.h +widgets/order_widget.h +widgets/osk_widget.h +widgets/rail_widget.h +widgets/road_widget.h +widgets/settings_widget.h +widgets/sign_widget.h +widgets/smallmap_widget.h +widgets/station_widget.h +widgets/statusbar_widget.h +widgets/story_widget.h +widgets/subsidy_widget.h +widgets/terraform_widget.h +widgets/timetable_widget.h +widgets/toolbar_widget.h +widgets/town_widget.h +widgets/transparency_widget.h +widgets/tree_widget.h +widgets/vehicle_widget.h +widgets/viewport_widget.h +widgets/waypoint_widget.h + +# Command handlers +aircraft_cmd.cpp +autoreplace_cmd.cpp +clear_cmd.cpp +company_cmd.cpp +depot_cmd.cpp +group_cmd.cpp +industry_cmd.cpp +misc_cmd.cpp +object_cmd.cpp +order_cmd.cpp +rail_cmd.cpp +road_cmd.cpp +roadveh_cmd.cpp +ship_cmd.cpp +signs_cmd.cpp +station_cmd.cpp +terraform_cmd.cpp +timetable_cmd.cpp +town_cmd.cpp +train_cmd.cpp +tree_cmd.cpp +tunnelbridge_cmd.cpp +vehicle_cmd.cpp +void_cmd.cpp +water_cmd.cpp +waypoint_cmd.cpp + +# Save/Load handlers +saveload/afterload.cpp +saveload/ai_sl.cpp +saveload/airport_sl.cpp +saveload/animated_tile_sl.cpp +saveload/autoreplace_sl.cpp +saveload/cargomonitor_sl.cpp +saveload/cargopacket_sl.cpp +saveload/cheat_sl.cpp +saveload/company_sl.cpp +saveload/depot_sl.cpp +saveload/economy_sl.cpp +saveload/engine_sl.cpp +saveload/game_sl.cpp +saveload/gamelog_sl.cpp +saveload/goal_sl.cpp +saveload/group_sl.cpp +saveload/industry_sl.cpp +saveload/labelmaps_sl.cpp +saveload/linkgraph_sl.cpp +saveload/map_sl.cpp +saveload/misc_sl.cpp +saveload/newgrf_sl.cpp +saveload/newgrf_sl.h +saveload/object_sl.cpp +saveload/oldloader.cpp +saveload/oldloader.h +saveload/oldloader_sl.cpp +saveload/order_sl.cpp +saveload/saveload.cpp +saveload/saveload.h +saveload/saveload_filter.h +saveload/saveload_internal.h +saveload/signs_sl.cpp +saveload/station_sl.cpp +saveload/storage_sl.cpp +saveload/strings_sl.cpp +saveload/story_sl.cpp +saveload/subsidy_sl.cpp +saveload/town_sl.cpp +saveload/vehicle_sl.cpp +saveload/waypoint_sl.cpp + +# Tables +table/airport_defaults.h +table/airport_movement.h +table/airporttile_ids.h +table/airporttiles.h +table/animcursors.h +table/autorail.h +table/bridge_land.h +table/build_industry.h +table/cargo_const.h +table/clear_land.h +table/control_codes.h +table/elrail_data.h +table/engines.h +table/genland.h +table/heightmap_colours.h +table/industry_land.h +table/landscape_sprite.h +table/newgrf_debug_data.h +table/object_land.h +table/palette_convert.h +table/palettes.h +table/pricebase.h +table/railtypes.h +table/road_land.h +table/roadveh_movement.h +../objs/settings/table/settings.h +table/sprites.h +table/station_land.h +table/strgen_tables.h +../objs/langs/table/strings.h +table/town_land.h +table/townname.h +table/track_land.h +table/train_cmd.h +table/tree_land.h +table/unicode.h +table/water_land.h + +# MD5 +3rdparty/md5/md5.cpp +3rdparty/md5/md5.h + +# Script +script/script_config.cpp +script/script_config.hpp +script/script_fatalerror.hpp +script/script_info.cpp +script/script_info.hpp +script/script_info_dummy.cpp +script/script_instance.cpp +script/script_instance.hpp +script/script_scanner.cpp +script/script_scanner.hpp +script/script_storage.hpp +script/script_suspend.hpp +script/squirrel.cpp +script/squirrel.hpp +script/squirrel_class.hpp +script/squirrel_helper.hpp +script/squirrel_helper_type.hpp +script/squirrel_std.cpp +script/squirrel_std.hpp + +# Squirrel +3rdparty/squirrel/squirrel/sqapi.cpp +3rdparty/squirrel/squirrel/sqbaselib.cpp +3rdparty/squirrel/squirrel/sqclass.cpp +3rdparty/squirrel/squirrel/sqcompiler.cpp +3rdparty/squirrel/squirrel/sqdebug.cpp +3rdparty/squirrel/squirrel/sqfuncstate.cpp +3rdparty/squirrel/squirrel/sqlexer.cpp +3rdparty/squirrel/squirrel/sqmem.cpp +3rdparty/squirrel/squirrel/sqobject.cpp +3rdparty/squirrel/squirrel/sqstate.cpp +3rdparty/squirrel/sqstdlib/sqstdaux.cpp +3rdparty/squirrel/sqstdlib/sqstdmath.cpp +3rdparty/squirrel/squirrel/sqtable.cpp +3rdparty/squirrel/squirrel/sqvm.cpp + +# Squirrel headers +3rdparty/squirrel/squirrel/sqarray.h +3rdparty/squirrel/squirrel/sqclass.h +3rdparty/squirrel/squirrel/sqclosure.h +3rdparty/squirrel/squirrel/sqcompiler.h +3rdparty/squirrel/squirrel/sqfuncproto.h +3rdparty/squirrel/squirrel/sqfuncstate.h +3rdparty/squirrel/squirrel/sqlexer.h +3rdparty/squirrel/squirrel/sqobject.h +3rdparty/squirrel/squirrel/sqopcodes.h +3rdparty/squirrel/squirrel/sqpcheader.h +3rdparty/squirrel/squirrel/sqstate.h +3rdparty/squirrel/include/sqstdaux.h +3rdparty/squirrel/include/sqstdmath.h +3rdparty/squirrel/include/sqstdstring.h +3rdparty/squirrel/squirrel/sqstring.h +3rdparty/squirrel/squirrel/sqtable.h +3rdparty/squirrel/include/squirrel.h +3rdparty/squirrel/squirrel/squserdata.h +3rdparty/squirrel/squirrel/squtils.h +3rdparty/squirrel/squirrel/sqvm.h + +# AI Core +ai/ai.hpp +ai/ai_config.cpp +ai/ai_config.hpp +ai/ai_core.cpp +ai/ai_gui.cpp +ai/ai_gui.hpp +ai/ai_info.cpp +ai/ai_info.hpp +ai/ai_instance.cpp +ai/ai_instance.hpp +ai/ai_scanner.cpp +ai/ai_scanner.hpp + +# AI API +script/api/ai_changelog.hpp + +# Game API +script/api/game_changelog.hpp + +# Game Core +game/game.hpp +game/game_config.cpp +game/game_config.hpp +game/game_core.cpp +game/game_info.cpp +game/game_info.hpp +game/game_instance.cpp +game/game_instance.hpp +game/game_scanner.cpp +game/game_scanner.hpp +game/game_text.cpp +game/game_text.hpp + +# Script API +script/api/script_accounting.hpp +script/api/script_admin.hpp +script/api/script_airport.hpp +script/api/script_base.hpp +script/api/script_basestation.hpp +script/api/script_bridge.hpp +script/api/script_bridgelist.hpp +script/api/script_cargo.hpp +script/api/script_cargolist.hpp +script/api/script_cargomonitor.hpp +script/api/script_company.hpp +script/api/script_companymode.hpp +script/api/script_controller.hpp +script/api/script_date.hpp +script/api/script_depotlist.hpp +script/api/script_engine.hpp +script/api/script_enginelist.hpp +script/api/script_error.hpp +script/api/script_event.hpp +script/api/script_event_types.hpp +script/api/script_execmode.hpp +script/api/script_game.hpp +script/api/script_gamesettings.hpp +script/api/script_goal.hpp +script/api/script_group.hpp +script/api/script_grouplist.hpp +script/api/script_industry.hpp +script/api/script_industrylist.hpp +script/api/script_industrytype.hpp +script/api/script_industrytypelist.hpp +script/api/script_info_docs.hpp +script/api/script_infrastructure.hpp +script/api/script_list.hpp +script/api/script_log.hpp +script/api/script_map.hpp +script/api/script_marine.hpp +script/api/script_news.hpp +script/api/script_object.hpp +script/api/script_order.hpp +script/api/script_rail.hpp +script/api/script_railtypelist.hpp +script/api/script_road.hpp +script/api/script_sign.hpp +script/api/script_signlist.hpp +script/api/script_station.hpp +script/api/script_stationlist.hpp +script/api/script_story_page.hpp +script/api/script_storypagelist.hpp +script/api/script_storypageelementlist.hpp +script/api/script_subsidy.hpp +script/api/script_subsidylist.hpp +script/api/script_testmode.hpp +script/api/script_text.hpp +script/api/script_tile.hpp +script/api/script_tilelist.hpp +script/api/script_town.hpp +script/api/script_townlist.hpp +script/api/script_tunnel.hpp +script/api/script_types.hpp +script/api/script_vehicle.hpp +script/api/script_vehiclelist.hpp +script/api/script_viewport.hpp +script/api/script_waypoint.hpp +script/api/script_waypointlist.hpp +script/api/script_window.hpp + +# Script API Implementation +script/api/script_accounting.cpp +script/api/script_admin.cpp +script/api/script_airport.cpp +script/api/script_base.cpp +script/api/script_basestation.cpp +script/api/script_bridge.cpp +script/api/script_bridgelist.cpp +script/api/script_cargo.cpp +script/api/script_cargolist.cpp +script/api/script_cargomonitor.cpp +script/api/script_company.cpp +script/api/script_companymode.cpp +script/api/script_controller.cpp +script/api/script_date.cpp +script/api/script_depotlist.cpp +script/api/script_engine.cpp +script/api/script_enginelist.cpp +script/api/script_error.cpp +script/api/script_event.cpp +script/api/script_event_types.cpp +script/api/script_execmode.cpp +script/api/script_game.cpp +script/api/script_gamesettings.cpp +script/api/script_goal.cpp +script/api/script_group.cpp +script/api/script_grouplist.cpp +script/api/script_industry.cpp +script/api/script_industrylist.cpp +script/api/script_industrytype.cpp +script/api/script_industrytypelist.cpp +script/api/script_infrastructure.cpp +script/api/script_list.cpp +script/api/script_log.cpp +script/api/script_map.cpp +script/api/script_marine.cpp +script/api/script_news.cpp +script/api/script_object.cpp +script/api/script_order.cpp +script/api/script_rail.cpp +script/api/script_railtypelist.cpp +script/api/script_road.cpp +script/api/script_sign.cpp +script/api/script_signlist.cpp +script/api/script_station.cpp +script/api/script_stationlist.cpp +script/api/script_story_page.cpp +script/api/script_storypagelist.cpp +script/api/script_storypageelementlist.cpp +script/api/script_subsidy.cpp +script/api/script_subsidylist.cpp +script/api/script_testmode.cpp +script/api/script_text.cpp +script/api/script_tile.cpp +script/api/script_tilelist.cpp +script/api/script_town.cpp +script/api/script_townlist.cpp +script/api/script_tunnel.cpp +script/api/script_vehicle.cpp +script/api/script_vehiclelist.cpp +script/api/script_viewport.cpp +script/api/script_waypoint.cpp +script/api/script_waypointlist.cpp +script/api/script_window.cpp + +# Blitters +#if DEDICATED +#else +blitter/32bpp_anim.cpp +blitter/32bpp_anim.hpp +#if SSE +blitter/32bpp_anim_sse4.cpp +blitter/32bpp_anim_sse4.hpp +#end +blitter/32bpp_base.cpp +blitter/32bpp_base.hpp +blitter/32bpp_optimized.cpp +blitter/32bpp_optimized.hpp +blitter/32bpp_simple.cpp +blitter/32bpp_simple.hpp +#if SSE +blitter/32bpp_sse_func.hpp +blitter/32bpp_sse_type.h +blitter/32bpp_sse2.cpp +blitter/32bpp_sse2.hpp +blitter/32bpp_sse4.cpp +blitter/32bpp_sse4.hpp +blitter/32bpp_ssse3.cpp +blitter/32bpp_ssse3.hpp +#end +blitter/8bpp_base.cpp +blitter/8bpp_base.hpp +blitter/8bpp_optimized.cpp +blitter/8bpp_optimized.hpp +blitter/8bpp_simple.cpp +blitter/8bpp_simple.hpp +#end +blitter/base.cpp +blitter/base.hpp +blitter/factory.hpp +blitter/null.cpp +blitter/null.hpp + +# Drivers +music/music_driver.hpp +sound/sound_driver.hpp +video/video_driver.hpp + +# Sprite loaders +spriteloader/grf.cpp +spriteloader/grf.hpp +spriteloader/spriteloader.hpp + +# NewGRF +newgrf.cpp +newgrf_airport.cpp +newgrf_airporttiles.cpp +newgrf_canal.cpp +newgrf_cargo.cpp +newgrf_commons.cpp +newgrf_config.cpp +newgrf_engine.cpp +newgrf_generic.cpp +newgrf_house.cpp +newgrf_industries.cpp +newgrf_industrytiles.cpp +newgrf_object.cpp +newgrf_railtype.cpp +newgrf_sound.cpp +newgrf_spritegroup.cpp +newgrf_station.cpp +newgrf_storage.cpp +newgrf_text.cpp +newgrf_town.cpp +newgrf_townname.cpp + +# Map Accessors +bridge_map.cpp +bridge_map.h +clear_map.h +industry_map.h +object_map.h +rail_map.h +road_map.cpp +road_map.h +station_map.h +tile_map.h +town_map.h +tree_map.h +tunnel_map.cpp +tunnel_map.h +tunnelbridge_map.h +void_map.h +water_map.h + +# Misc +misc/array.hpp +misc/binaryheap.hpp +misc/blob.hpp +misc/countedobj.cpp +misc/countedptr.hpp +misc/dbg_helpers.cpp +misc/dbg_helpers.h +misc/fixedsizearray.hpp +misc/getoptdata.cpp +misc/getoptdata.h +misc/hashtable.hpp +misc/str.hpp + +# Network Core +network/core/address.cpp +network/core/address.h +network/core/config.h +network/core/core.cpp +network/core/core.h +network/core/game.h +network/core/host.cpp +network/core/host.h +network/core/os_abstraction.h +network/core/packet.cpp +network/core/packet.h +network/core/tcp.cpp +network/core/tcp.h +network/core/tcp_admin.cpp +network/core/tcp_admin.h +network/core/tcp_connect.cpp +network/core/tcp_content.cpp +network/core/tcp_content.h +network/core/tcp_game.cpp +network/core/tcp_game.h +network/core/tcp_http.cpp +network/core/tcp_http.h +network/core/tcp_listen.h +network/core/udp.cpp +network/core/udp.h + +# Pathfinder +pathfinder/follow_track.hpp +pathfinder/opf/opf_ship.cpp +pathfinder/opf/opf_ship.h +pathfinder/pathfinder_func.h +pathfinder/pathfinder_type.h +pathfinder/pf_performance_timer.hpp + +# NPF +pathfinder/npf/aystar.cpp +pathfinder/npf/aystar.h +pathfinder/npf/npf.cpp +pathfinder/npf/npf_func.h +pathfinder/npf/queue.cpp +pathfinder/npf/queue.h + +# YAPF +pathfinder/yapf/nodelist.hpp +pathfinder/yapf/yapf.h +pathfinder/yapf/yapf.hpp +pathfinder/yapf/yapf_base.hpp +pathfinder/yapf/yapf_cache.h +pathfinder/yapf/yapf_common.hpp +pathfinder/yapf/yapf_costbase.hpp +pathfinder/yapf/yapf_costcache.hpp +pathfinder/yapf/yapf_costrail.hpp +pathfinder/yapf/yapf_destrail.hpp +pathfinder/yapf/yapf_node.hpp +pathfinder/yapf/yapf_node_rail.hpp +pathfinder/yapf/yapf_node_road.hpp +pathfinder/yapf/yapf_node_ship.hpp +pathfinder/yapf/yapf_rail.cpp +pathfinder/yapf/yapf_road.cpp +pathfinder/yapf/yapf_ship.cpp +pathfinder/yapf/yapf_type.hpp + +# Video +video/dedicated_v.cpp +video/null_v.cpp +#if DEDICATED +#else +#if ALLEGRO + video/allegro_v.cpp +#end +#if SDL + video/sdl_v.cpp +#end +#if WIN32 + video/win32_v.cpp +#end +#if WINCE + video/win32_v.cpp +#end +#end + +# Music +#if DEDICATED +#else +#if ALLEGRO + music/allegro_m.cpp +#end +#if DIRECTMUSIC + music/dmusic.cpp +#end +#end +music/null_m.cpp +#if DEDICATED +#else +#if WIN32 + music/win32_m.cpp +#else + #if WINCE + #else + #if PSP + #else + #if DOS + #else + #if MORPHOS + #else + music/extmidi.cpp + #end + #end + #end + #end +#end +#if BEOS + music/bemidi.cpp +#end +#if LIBTIMIDITY + music/libtimidity.cpp +#end +#end + +# Sound +sound/null_s.cpp +#if DEDICATED +#else +#if ALLEGRO + sound/allegro_s.cpp +#end +#if SDL + sound/sdl_s.cpp +#end +#if WIN32 + sound/win32_s.cpp +#end +#end + +#if OSX +# OSX Files + os/macosx/macos.mm + + #if DEDICATED + #else + music/qtmidi.cpp + #end + + #if COCOA + video/cocoa/cocoa_v.mm + video/cocoa/event.mm + video/cocoa/fullscreen.mm + video/cocoa/wnd_quartz.mm + video/cocoa/wnd_quickdraw.mm + music/cocoa_m.cpp + sound/cocoa_s.cpp + os/macosx/splash.cpp + #end +#end + +# Windows files +#if WIN32 + os/windows/crashlog_win.cpp + os/windows/ottdres.rc + os/windows/win32.cpp +#end +#if WINCE + os/windows/ottdres.rc + os/windows/win32.cpp +#end + +# Threading +thread/thread.h +#if HAVE_THREAD + #if WIN32 + thread/thread_win32.cpp + #else + #if OS2 + thread/thread_os2.cpp + #else + #if MORPHOS + thread/thread_morphos.cpp + #else + thread/thread_pthread.cpp + #end + #end + #end +#else + thread/thread_none.cpp +#end diff --git a/src/3rdparty/README.licensing b/src/3rdparty/README.licensing new file mode 100644 index 0000000..112b02a --- /dev/null +++ b/src/3rdparty/README.licensing @@ -0,0 +1,3 @@ +The files in this directory are not licensed under the same terms as the +rest of OpenTTD. Licensing details can be found in OpenTTD's readme.txt +and in this directory or subdirectories as well. diff --git a/src/3rdparty/md5/md5.cpp b/src/3rdparty/md5/md5.cpp new file mode 100644 index 0000000..2111a8e --- /dev/null +++ b/src/3rdparty/md5/md5.cpp @@ -0,0 +1,325 @@ +/* $Id$ */ + +/** @file md5.cpp Creating MD5 checksums of files. */ + +/* + Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ + +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.c is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2007-12-24 Changed to C++ and adapted to OpenTTD source + 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order + either statically or dynamically; added missing #include + in library. + 2002-03-11 lpd Corrected argument list for main(), and added int return + type, in test program and T value program. + 2002-02-21 lpd Added missing #include in test program. + 2000-07-03 lpd Patched to eliminate warnings about "constant is + unsigned in ANSI C, signed in traditional"; made test program + self-checking. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +#include "../../stdafx.h" +#include "../../core/endian_func.hpp" +#include "md5.h" + +#include "../../safeguards.h" + +#define T_MASK ((uint32)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + +static inline void Md5Set1(const uint32 *X, uint32 *a, const uint32 *b, const uint32 *c, const uint32 *d, const uint8 k, const uint8 s, const uint32 Ti) +{ + uint32 t = (*b & *c) | (~*b & *d); + t += *a + X[k] + Ti; + *a = ROL(t, s) + *b; +} + +static inline void Md5Set2(const uint32 *X, uint32 *a, const uint32 *b, const uint32 *c, const uint32 *d, const uint8 k, const uint8 s, const uint32 Ti) +{ + uint32 t = (*b & *d) | (*c & ~*d); + t += *a + X[k] + Ti; + *a = ROL(t, s) + *b; +} + + +static inline void Md5Set3(const uint32 *X, uint32 *a, const uint32 *b, const uint32 *c, const uint32 *d, const uint8 k, const uint8 s, const uint32 Ti) +{ + uint32 t = *b ^ *c ^ *d; + t += *a + X[k] + Ti; + *a = ROL(t, s) + *b; +} + +static inline void Md5Set4(const uint32 *X, uint32 *a, const uint32 *b, const uint32 *c, const uint32 *d, const uint8 k, const uint8 s, const uint32 Ti) +{ + uint32 t = *c ^ (*b | ~*d); + t += *a + X[k] + Ti; + *a = ROL(t, s) + *b; +} + +Md5::Md5() +{ + count[0] = 0; + count[1] = 0; + abcd[0] = 0x67452301; + abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + abcd[3] = 0x10325476; +} + +void Md5::Process(const uint8 *data /*[64]*/) +{ + uint32 a = this->abcd[0]; + uint32 b = this->abcd[1]; + uint32 c = this->abcd[2]; + uint32 d = this->abcd[3]; + + uint32 X[16]; + + /* Convert the uint8 data to uint32 LE */ + const uint32 *px = (const uint32 *)data; + for (uint i = 0; i < 16; i++) { + X[i] = TO_LE32(*px); + px++; + } + + /* Round 1. */ + Md5Set1(X, &a, &b, &c, &d, 0, 7, T1); + Md5Set1(X, &d, &a, &b, &c, 1, 12, T2); + Md5Set1(X, &c, &d, &a, &b, 2, 17, T3); + Md5Set1(X, &b, &c, &d, &a, 3, 22, T4); + Md5Set1(X, &a, &b, &c, &d, 4, 7, T5); + Md5Set1(X, &d, &a, &b, &c, 5, 12, T6); + Md5Set1(X, &c, &d, &a, &b, 6, 17, T7); + Md5Set1(X, &b, &c, &d, &a, 7, 22, T8); + Md5Set1(X, &a, &b, &c, &d, 8, 7, T9); + Md5Set1(X, &d, &a, &b, &c, 9, 12, T10); + Md5Set1(X, &c, &d, &a, &b, 10, 17, T11); + Md5Set1(X, &b, &c, &d, &a, 11, 22, T12); + Md5Set1(X, &a, &b, &c, &d, 12, 7, T13); + Md5Set1(X, &d, &a, &b, &c, 13, 12, T14); + Md5Set1(X, &c, &d, &a, &b, 14, 17, T15); + Md5Set1(X, &b, &c, &d, &a, 15, 22, T16); + + /* Round 2. */ + Md5Set2(X, &a, &b, &c, &d, 1, 5, T17); + Md5Set2(X, &d, &a, &b, &c, 6, 9, T18); + Md5Set2(X, &c, &d, &a, &b, 11, 14, T19); + Md5Set2(X, &b, &c, &d, &a, 0, 20, T20); + Md5Set2(X, &a, &b, &c, &d, 5, 5, T21); + Md5Set2(X, &d, &a, &b, &c, 10, 9, T22); + Md5Set2(X, &c, &d, &a, &b, 15, 14, T23); + Md5Set2(X, &b, &c, &d, &a, 4, 20, T24); + Md5Set2(X, &a, &b, &c, &d, 9, 5, T25); + Md5Set2(X, &d, &a, &b, &c, 14, 9, T26); + Md5Set2(X, &c, &d, &a, &b, 3, 14, T27); + Md5Set2(X, &b, &c, &d, &a, 8, 20, T28); + Md5Set2(X, &a, &b, &c, &d, 13, 5, T29); + Md5Set2(X, &d, &a, &b, &c, 2, 9, T30); + Md5Set2(X, &c, &d, &a, &b, 7, 14, T31); + Md5Set2(X, &b, &c, &d, &a, 12, 20, T32); + + /* Round 3. */ + Md5Set3(X, &a, &b, &c, &d, 5, 4, T33); + Md5Set3(X, &d, &a, &b, &c, 8, 11, T34); + Md5Set3(X, &c, &d, &a, &b, 11, 16, T35); + Md5Set3(X, &b, &c, &d, &a, 14, 23, T36); + Md5Set3(X, &a, &b, &c, &d, 1, 4, T37); + Md5Set3(X, &d, &a, &b, &c, 4, 11, T38); + Md5Set3(X, &c, &d, &a, &b, 7, 16, T39); + Md5Set3(X, &b, &c, &d, &a, 10, 23, T40); + Md5Set3(X, &a, &b, &c, &d, 13, 4, T41); + Md5Set3(X, &d, &a, &b, &c, 0, 11, T42); + Md5Set3(X, &c, &d, &a, &b, 3, 16, T43); + Md5Set3(X, &b, &c, &d, &a, 6, 23, T44); + Md5Set3(X, &a, &b, &c, &d, 9, 4, T45); + Md5Set3(X, &d, &a, &b, &c, 12, 11, T46); + Md5Set3(X, &c, &d, &a, &b, 15, 16, T47); + Md5Set3(X, &b, &c, &d, &a, 2, 23, T48); + + /* Round 4. */ + Md5Set4(X, &a, &b, &c, &d, 0, 6, T49); + Md5Set4(X, &d, &a, &b, &c, 7, 10, T50); + Md5Set4(X, &c, &d, &a, &b, 14, 15, T51); + Md5Set4(X, &b, &c, &d, &a, 5, 21, T52); + Md5Set4(X, &a, &b, &c, &d, 12, 6, T53); + Md5Set4(X, &d, &a, &b, &c, 3, 10, T54); + Md5Set4(X, &c, &d, &a, &b, 10, 15, T55); + Md5Set4(X, &b, &c, &d, &a, 1, 21, T56); + Md5Set4(X, &a, &b, &c, &d, 8, 6, T57); + Md5Set4(X, &d, &a, &b, &c, 15, 10, T58); + Md5Set4(X, &c, &d, &a, &b, 6, 15, T59); + Md5Set4(X, &b, &c, &d, &a, 13, 21, T60); + Md5Set4(X, &a, &b, &c, &d, 4, 6, T61); + Md5Set4(X, &d, &a, &b, &c, 11, 10, T62); + Md5Set4(X, &c, &d, &a, &b, 2, 15, T63); + Md5Set4(X, &b, &c, &d, &a, 9, 21, T64); + + /* Then perform the following additions. (That is increment each + * of the four registers by the value it had before this block + * was started.) */ + this->abcd[0] += a; + this->abcd[1] += b; + this->abcd[2] += c; + this->abcd[3] += d; +} + +void Md5::Append(const void *data, const size_t nbytes) +{ + const uint8 *p = (const uint8 *)data; + size_t left = nbytes; + const size_t offset = (this->count[0] >> 3) & 63; + const uint32 nbits = (uint32)(nbytes << 3); + + if (nbytes <= 0) return; + + /* Update the message length. */ + this->count[1] += (uint32)(nbytes >> 29); + this->count[0] += nbits; + + if (this->count[0] < nbits) this->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + size_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(this->buf + offset, p, copy); + + if (offset + copy < 64) return; + + p += copy; + left -= copy; + this->Process(this->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) this->Process(p); + + /* Process a final partial block. */ + if (left) memcpy(this->buf, p, left); +} + +void Md5::Finish(uint8 digest[16]) +{ + static const uint8 pad[64] = { + 0x80, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + uint8 data[8]; + + /* Save the length before padding. */ + for (uint i = 0; i < 8; ++i) { + data[i] = (uint8)(this->count[i >> 2] >> ((i & 3) << 3)); + } + + /* Pad to 56 bytes mod 64. */ + this->Append(pad, ((55 - (this->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + this->Append(data, 8); + + for (uint i = 0; i < 16; ++i) { + digest[i] = (uint8)(this->abcd[i >> 2] >> ((i & 3) << 3)); + } +} diff --git a/src/3rdparty/md5/md5.h b/src/3rdparty/md5/md5.h new file mode 100644 index 0000000..9748dc4 --- /dev/null +++ b/src/3rdparty/md5/md5.h @@ -0,0 +1,72 @@ +/* $Id$ */ + +/** @file md5.h Functions to create MD5 checksums. */ + +/* + Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ + +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.h is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2007-12-24 Changed to C++ and adapted to OpenTTD source + 2002-04-13 lpd Removed support for non-ANSI compilers; removed + references to Ghostscript; clarified derivation from RFC 1321; + now handles byte order either statically or dynamically. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke . + 1999-05-03 lpd Original version. + */ + +#ifndef MD5_INCLUDED +#define MD5_INCLUDED + +struct Md5 { +private: + uint32 count[2]; ///< message length in bits, lsw first + uint32 abcd[4]; ///< digest buffer + uint8 buf[64]; ///< accumulate block + + void Process(const uint8 *data); + +public: + Md5(); + void Append(const void *data, const size_t nbytes); + void Finish(uint8 digest[16]); +}; + +#endif /* MD5_INCLUDED */ diff --git a/src/3rdparty/os2/getaddrinfo.c b/src/3rdparty/os2/getaddrinfo.c new file mode 100644 index 0000000..3cdda21 --- /dev/null +++ b/src/3rdparty/os2/getaddrinfo.c @@ -0,0 +1,299 @@ +/* + * This file is part of libESMTP, a library for submission of RFC 2822 + * formatted electronic mail messages using the SMTP protocol described + * in RFC 2821. + * + * Copyright (C) 2001,2002 Brian Stafford + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* An emulation of the RFC 2553 / Posix getaddrinfo resolver interface. + */ + +#if !HAVE_GETADDRINFO + +/* Need to turn off Posix features in glibc to build this */ +#undef _POSIX_C_SOURCE +#undef _XOPEN_SOURCE + +#include "getaddrinfo.h" +//#include "compat/inet_pton.h" + +#include +#include +#include +#include +#include +#include +#include + +static struct addrinfo * +dup_addrinfo (struct addrinfo *info, void *addr, size_t addrlen) { + struct addrinfo *ret; + + ret = malloc (sizeof (struct addrinfo)); + if (ret == NULL) + return NULL; + memcpy (ret, info, sizeof (struct addrinfo)); + ret->ai_addr = malloc (addrlen); + if (ret->ai_addr == NULL) { + free (ret); + return NULL; + } + memcpy (ret->ai_addr, addr, addrlen); + ret->ai_addrlen = addrlen; + return ret; +} + +int +getaddrinfo (const char *nodename, const char *servname, + const struct addrinfo *hints, struct addrinfo **res) +{ + struct hostent *hp; + struct servent *servent; + const char *socktype; + int port; + struct addrinfo hint, result; + struct addrinfo *ai, *sai, *eai; + char **addrs; + + if (servname == NULL && nodename == NULL) + return EAI_NONAME; + + memset (&result, 0, sizeof result); + + /* default for hints */ + if (hints == NULL) { + memset (&hint, 0, sizeof hint); + hint.ai_family = PF_UNSPEC; + hints = &hint; + } + + if (servname == NULL) + port = 0; + else { + /* check for tcp or udp sockets only */ + if (hints->ai_socktype == SOCK_STREAM) + socktype = "tcp"; + else if (hints->ai_socktype == SOCK_DGRAM) + socktype = "udp"; + else + return EAI_SERVICE; + result.ai_socktype = hints->ai_socktype; + + /* Note: maintain port in host byte order to make debugging easier */ + if (isdigit (*servname)) + port = strtol (servname, NULL, 10); + else if ((servent = getservbyname (servname, socktype)) != NULL) + port = ntohs (servent->s_port); + else + return EAI_NONAME; + } + + /* if nodename == NULL refer to the local host for a client or any + for a server */ + if (nodename == NULL) { + struct sockaddr_in sin; + + /* check protocol family is PF_UNSPEC or PF_INET - could try harder + for IPv6 but that's more code than I'm prepared to write */ + if (hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET) + result.ai_family = AF_INET; + else + return EAI_FAMILY; + + sin.sin_family = result.ai_family; + sin.sin_port = htons (port); + if (hints->ai_flags & AI_PASSIVE) + sin.sin_addr.s_addr = htonl (INADDR_ANY); + else + sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + /* Duplicate result and addr and return */ + *res = dup_addrinfo (&result, &sin, sizeof sin); + return (*res == NULL) ? EAI_MEMORY : 0; + } + + /* If AI_NUMERIC is specified, use inet_pton to translate numbers and + dots notation. */ + if (hints->ai_flags & AI_NUMERICHOST) { + struct sockaddr_in sin; + + /* check protocol family is PF_UNSPEC or PF_INET */ + if (hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET) + result.ai_family = AF_INET; + else + return EAI_FAMILY; + + sin.sin_family = result.ai_family; + sin.sin_port = htons (port); + if (inet_pton(result.ai_family, nodename, &sin.sin_addr)==0) + return EAI_NONAME; + sin.sin_addr.s_addr = inet_addr (nodename); + /* Duplicate result and addr and return */ + *res = dup_addrinfo (&result, &sin, sizeof sin); + return (*res == NULL) ? EAI_MEMORY : 0; + } + +#if HAVE_H_ERRNO + h_errno = 0; +#endif + errno = 0; + hp = gethostbyname(nodename); + if (hp == NULL) { +#ifdef EAI_SYSTEM + if (errno != 0) { + return EAI_SYSTEM; + } +#endif + switch (h_errno) { + case HOST_NOT_FOUND: + return EAI_NODATA; + case NO_DATA: + return EAI_NODATA; +#if defined(NO_ADDRESS) && NO_ADDRESS != NO_DATA + case NO_ADDRESS: + return EAI_NODATA; +#endif + case NO_RECOVERY: + return EAI_FAIL; + case TRY_AGAIN: + return EAI_AGAIN; + default: + return EAI_FAIL; + } + return EAI_FAIL; + } + + /* Check that the address family is acceptable. + */ + switch (hp->h_addrtype) { + case AF_INET: + if (!(hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET)) + return EAI_FAMILY; + break; +#ifndef __OS2__ + case AF_INET6: + if (!(hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET6)) + return EAI_FAMILY; + break; +#endif + default: + return EAI_FAMILY; + } + + /* For each element pointed to by hp, create an element in the + result linked list. */ + sai = eai = NULL; + for (addrs = hp->h_addr_list; *addrs != NULL; addrs++) { + struct sockaddr sa; + size_t addrlen; + + if (hp->h_length < 1) + continue; + sa.sa_family = hp->h_addrtype; + switch (hp->h_addrtype) { + case AF_INET: + ((struct sockaddr_in *) &sa)->sin_port = htons (port); + memcpy (&((struct sockaddr_in *) &sa)->sin_addr, + *addrs, hp->h_length); + addrlen = sizeof (struct sockaddr_in); + break; +#ifndef __OS2__ + case AF_INET6: +#if SIN6_LEN + ((struct sockaddr_in6 *) &sa)->sin6_len = hp->h_length; +#endif + ((struct sockaddr_in6 *) &sa)->sin6_port = htons (port); + memcpy (&((struct sockaddr_in6 *) &sa)->sin6_addr, + *addrs, hp->h_length); + addrlen = sizeof (struct sockaddr_in6); + break; +#endif + default: + continue; + } + + result.ai_family = hp->h_addrtype; + ai = dup_addrinfo (&result, &sa, addrlen); + if (ai == NULL) { + freeaddrinfo (sai); + return EAI_MEMORY; + } + if (sai == NULL) + sai = ai; + else + eai->ai_next = ai; + eai = ai; + } + + if (sai == NULL) { + return EAI_NODATA; + } + + if (hints->ai_flags & AI_CANONNAME) { + sai->ai_canonname = malloc (strlen (hp->h_name) + 1); + if (sai->ai_canonname == NULL) { + freeaddrinfo (sai); + return EAI_MEMORY; + } + strcpy (sai->ai_canonname, hp->h_name); + } + + *res = sai; + return 0; +} + +void +freeaddrinfo (struct addrinfo *ai) +{ + struct addrinfo *next; + + while (ai != NULL) { + next = ai->ai_next; + if (ai->ai_canonname != NULL) + free (ai->ai_canonname); + if (ai->ai_addr != NULL) + free (ai->ai_addr); + free (ai); + ai = next; + } +} + +const char * +gai_strerror (int ecode) +{ + static const char *eai_descr[] = { + "no error", + "address family for nodename not supported", /* EAI_ADDRFAMILY */ + "temporary failure in name resolution", /* EAI_AGAIN */ + "invalid value for ai_flags", /* EAI_BADFLAGS */ + "non-recoverable failure in name resolution", /* EAI_FAIL */ + "ai_family not supported", /* EAI_FAMILY */ + "memory allocation failure", /* EAI_MEMORY */ + "no address associated with nodename", /* EAI_NODATA */ + "nodename nor servname provided, or not known", /* EAI_NONAME */ + "servname not supported for ai_socktype", /* EAI_SERVICE */ + "ai_socktype not supported", /* EAI_SOCKTYPE */ + "system error returned in errno", /* EAI_SYSTEM */ + "argument buffer overflow", /* EAI_OVERFLOW */ + }; + + if (ecode < 0 || ecode > (int) (sizeof eai_descr/ sizeof eai_descr[0])) + return "unknown error"; + return eai_descr[ecode]; +} + +#endif /* HAVE_GETADDRINFO */ diff --git a/src/3rdparty/os2/getaddrinfo.h b/src/3rdparty/os2/getaddrinfo.h new file mode 100644 index 0000000..0a588a4 --- /dev/null +++ b/src/3rdparty/os2/getaddrinfo.h @@ -0,0 +1,101 @@ +#ifndef _getaddrinfo_h +#define _getaddrinfo_h + +/* + * Shamelessly duplicated from the fetchmail public sources + * for use by the Squid Project under GNU Public License. + * + * Update/Maintenance History: + * + * 15-Aug-2007 : Copied from fetchmail 6.3.8 + * - added protection around libray headers + * + * 16-Aug-2007 : Altered configure checks + * Un-hacked slightly to use system gethostbyname() + * + * Original License and code follows. + */ + +/* + * This file is part of libESMTP, a library for submission of RFC 2822 + * formatted electronic mail messages using the SMTP protocol described + * in RFC 2821. + * + * Copyright (C) 2001,2002 Brian Stafford + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Structure and prototypes taken from RFC 2553 */ + +/* SG 23/09/2007: +On Windows the following definitions are already available, may be that +this could be needed on some other platform */ +typedef int socklen_t; + +struct addrinfo { + int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */ + int ai_family; /* PF_xxx */ + int ai_socktype; /* SOCK_xxx */ + int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + socklen_t ai_addrlen; /* length of ai_addr */ + char *ai_canonname; /* canonical name for nodename */ + struct sockaddr *ai_addr; /* binary address */ + struct addrinfo *ai_next; /* next structure in linked list */ +}; + +/* Supposed to be defined in */ +#define AI_ADDRCONFIG 0 +#define AI_PASSIVE 1 /* Socket address is intended for `bind'. */ +#define AI_CANONNAME 2 /* Request for canonical name. */ +#define AI_NUMERICHOST 4 /* Don't use name resolution. */ + +/* Supposed to be defined in */ +#define EAI_ADDRFAMILY 1 /* address family for nodename not supported */ +#define EAI_AGAIN 2 /* temporary failure in name resolution */ +#define EAI_BADFLAGS 3 /* invalid value for ai_flags */ +#define EAI_FAIL 4 /* non-recoverable failure in name resolution */ +#define EAI_FAMILY 5 /* ai_family not supported */ +#define EAI_MEMORY 6 /* memory allocation failure */ +#define EAI_NODATA 7 /* no address associated with nodename */ +#define EAI_NONAME 8 /* nodename nor servname provided, or not known */ +#define EAI_SERVICE 9 /* servname not supported for ai_socktype */ +#define EAI_SOCKTYPE 10 /* ai_socktype not supported */ + +#ifndef EAI_SYSTEM +/* Not defined on mingw32. */ +#define EAI_SYSTEM 11 /* System error returned in `errno'. */ +#endif +#ifndef EAI_OVERFLOW +/* Not defined on mingw32. */ +#define EAI_OVERFLOW 12 /* Argument buffer overflow. */ +#endif + +#ifdef __cplusplus +extern "C" { +#endif +/* RFC 2553 / Posix resolver */ +int getaddrinfo (const char *nodename, const char *servname, + const struct addrinfo *hints, struct addrinfo **res); +/* Free addrinfo structure and associated storage */ +void freeaddrinfo (struct addrinfo *ai); + +/* Convert error return from getaddrinfo() to string */ +const char *gai_strerror (int code); +#ifdef __cplusplus +} +#endif + +#endif /* _getaddrinfo_h */ diff --git a/src/3rdparty/os2/getnameinfo.c b/src/3rdparty/os2/getnameinfo.c new file mode 100644 index 0000000..14fd89e --- /dev/null +++ b/src/3rdparty/os2/getnameinfo.c @@ -0,0 +1,367 @@ +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Issues to be discussed: + * - RFC2553 says that we should raise error on short buffer. X/Open says + * we need to truncate the result. We obey RFC2553 (and X/Open should be + * modified). ipngwg rough consensus seems to follow RFC2553. RFC3493 says + * nothing about it, but defines a new error code EAI_OVERFLOW which seems + * to be intended the code for this case. + * - What is "local" in NI_NOFQDN? (see comments in the code) + * - NI_NAMEREQD and NI_NUMERICHOST conflict with each other. + * - (KAME extension) always attach textual scopeid (fe80::1%lo0), if + * sin6_scope_id is filled - standardization status? + * - what should we do if we should do getservbyport("sctp")? + */ + +/* + * Considerations about thread-safeness + * The code in this file is thread-safe, and so the thread-safeness of + * getnameinfo() depends on the property of backend functions. + * - getservbyport() is not thread safe for most systems we are targeting. + * - getipnodebyaddr() is thread safe. However, many resolver libraries + * used in the function are not thread safe. + * - gethostbyaddr() is usually not thread safe. + */ + +#if !HAVE_GETNAMEINFO + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "getaddrinfo.h" +#include "getnameinfo.h" + +static const struct afd { + int a_af; + int a_addrlen; + int a_socklen; + int a_off; + int a_portoff; +} afdl [] = { +#if INET6 + {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6), + offsetof(struct sockaddr_in6, sin6_addr), + offsetof(struct sockaddr_in6, sin6_port)}, +#endif + {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in), + offsetof(struct sockaddr_in, sin_addr), + offsetof(struct sockaddr_in, sin_port)}, + {0, 0, 0, 0, 0}, +}; + +#if INET6 +static int ip6_parsenumeric __P((const struct sockaddr *, const char *, char *, + size_t, int)); +static int ip6_sa2str __P((const struct sockaddr_in6 *, char *, size_t, int)); +#endif + +int +getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) +const struct sockaddr *sa; +socklen_t salen; +char *host; +size_t hostlen; +char *serv; +size_t servlen; +int flags; +{ + const struct afd *afd; + struct servent *sp; + struct hostent *hp; + unsigned short port; + int family, i; + const char *addr; + uint32_t v4a; + char numserv[512]; + + if (sa == NULL) + return EAI_FAIL; + +#if HAVE_SA_LEN /*XXX*/ + if (sa->sa_len != salen) + return EAI_FAIL; +#endif + + family = sa->sa_family; + for (i = 0; afdl[i].a_af; i++) + if (afdl[i].a_af == family) { + afd = &afdl[i]; + goto found; + } + return EAI_FAMILY; + +found: + if (salen != afd->a_socklen) + return EAI_FAIL; + + /* network byte order */ + memcpy(&port, (const char *)sa + afd->a_portoff, sizeof(port)); + addr = (const char *)sa + afd->a_off; + + if (serv == NULL || servlen == 0) { + /* + * do nothing in this case. + * in case you are wondering if "&&" is more correct than + * "||" here: RFC3493 says that serv == NULL OR servlen == 0 + * means that the caller does not want the result. + */ + } else { + if (flags & NI_NUMERICSERV) + sp = NULL; + else { + sp = getservbyport(port, + (flags & NI_DGRAM) ? "udp" : "tcp"); + } + if (sp) { + if (strlen(sp->s_name) + 1 > servlen) + return EAI_OVERFLOW; + strncpy(serv, sp->s_name, servlen); + } else { + snprintf(numserv, sizeof(numserv), "%u", ntohs(port)); + if (strlen(numserv) + 1 > servlen) + return EAI_OVERFLOW; + strncpy(serv, numserv, servlen); + } + } + + switch (sa->sa_family) { + case AF_INET: + v4a = (uint32_t) + ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr); + if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) + flags |= NI_NUMERICHOST; + v4a >>= IN_CLASSA_NSHIFT; + if (v4a == 0) + flags |= NI_NUMERICHOST; + break; +#if INET6 + case AF_INET6: { + const struct sockaddr_in6 *sin6; + sin6 = (const struct sockaddr_in6 *)sa; + switch (sin6->sin6_addr.s6_addr[0]) { + case 0x00: + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) + ; + else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) + ; + else + flags |= NI_NUMERICHOST; + break; + default: + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) + flags |= NI_NUMERICHOST; + else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) + flags |= NI_NUMERICHOST; + break; + } + } + break; +#endif + } + if (host == NULL || hostlen == 0) { + /* + * do nothing in this case. + * in case you are wondering if "&&" is more correct than + * "||" here: RFC3493 says that host == NULL or hostlen == 0 + * means that the caller does not want the result. + */ + } else if (flags & NI_NUMERICHOST) { + /* NUMERICHOST and NAMEREQD conflicts with each other */ + if (flags & NI_NAMEREQD) + return EAI_NONAME; + + goto numeric; + } else { +#if USE_GETIPNODEBY + int h_error = 0; + hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error); +#else + hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af); +#if 0 // getnameinfo.c:161:9: error: variable 'h_error' set but not used +#if HAVE_H_ERRNO + h_error = h_errno; +#else + h_error = EINVAL; +#endif +#endif /* 0 */ +#endif + + if (hp) { +#if 0 + if (flags & NI_NOFQDN) { + /* + * According to RFC3493 section 6.2, NI_NOFQDN + * means "node name portion of the FQDN shall + * be returned for local hosts." The following + * code tries to implement it by returning the + * first label (the part before the first + * period) of the FQDN. However, it is not + * clear if this always makes sense, since the + * given address may be outside of "local + * hosts." Due to the unclear description, we + * disable the code in this implementation. + */ + char *p; + p = strchr(hp->h_name, '.'); + if (p) + *p = '\0'; + } +#endif + if (strlen(hp->h_name) + 1 > hostlen) { +#if USE_GETIPNODEBY + freehostent(hp); +#endif + return EAI_OVERFLOW; + } + strncpy(host, hp->h_name, hostlen); +#if USE_GETIPNODEBY + freehostent(hp); +#endif + } else { + if (flags & NI_NAMEREQD) + return EAI_NONAME; + +numeric: + switch (afd->a_af) { +#if INET6 + case AF_INET6: { + int error; + + if ((error = ip6_parsenumeric(sa, addr, host, + hostlen, + flags)) != 0) + return(error); + break; + } +#endif + default: + if (inet_ntop(afd->a_af, addr, host, + hostlen) == NULL) + return EAI_SYSTEM; + break; + } + } + } + return(0); +} + +#if INET6 +static int +ip6_parsenumeric(sa, addr, host, hostlen, flags) +const struct sockaddr *sa; +const char *addr; +char *host; +size_t hostlen; +int flags; +{ + int numaddrlen; + char numaddr[512]; + + if (inet_ntop(AF_INET6, addr, numaddr, sizeof(numaddr)) == NULL) + return EAI_SYSTEM; + + numaddrlen = strlen(numaddr); + if (numaddrlen + 1 > hostlen) /* don't forget terminator */ + return EAI_OVERFLOW; + strncpy(host, numaddr, hostlen); + + if (((const struct sockaddr_in6 *)sa)->sin6_scope_id) { + char zonebuf[SQUIDHOSTNAMELEN]; + int zonelen; + + zonelen = ip6_sa2str( + (const struct sockaddr_in6 *)(const void *)sa, + zonebuf, sizeof(zonebuf), flags); + if (zonelen < 0) + return EAI_OVERFLOW; + if (zonelen + 1 + numaddrlen + 1 > hostlen) + return EAI_OVERFLOW; + + /* construct */ + memcpy(host + numaddrlen + 1, zonebuf, + (size_t)zonelen); + host[numaddrlen] = SCOPE_DELIMITER; + host[numaddrlen + 1 + zonelen] = '\0'; + } + + return 0; +} + +/* ARGSUSED */ +static int +ip6_sa2str(sa6, buf, bufsiz, flags) +const struct sockaddr_in6 *sa6; +char *buf; +size_t bufsiz; +int flags; +{ + unsigned int ifindex; + const struct in6_addr *a6; + int n; + + ifindex = (unsigned int)sa6->sin6_scope_id; + a6 = &sa6->sin6_addr; + +#if NI_NUMERICSCOPE + if ((flags & NI_NUMERICSCOPE) != 0) { + n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id); + if (n < 0 || n >= bufsiz) + return -1; + else + return n; + } +#endif + + /* if_indextoname() does not take buffer size. not a good api... */ + if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6) || + IN6_IS_ADDR_MC_NODELOCAL(a6)) && bufsiz >= IF_NAMESIZE) { + char *p = if_indextoname(ifindex, buf); + if (p) + return (strlen(p)); + } + + /* last resort */ + n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id); + if (n < 0 || n >= bufsiz) + return -1; + else + return n; +} +#endif /* INET6 */ +#endif diff --git a/src/3rdparty/os2/getnameinfo.h b/src/3rdparty/os2/getnameinfo.h new file mode 100644 index 0000000..c1861aa --- /dev/null +++ b/src/3rdparty/os2/getnameinfo.h @@ -0,0 +1,29 @@ +#ifndef _getnameinfo_h +#define _getnameinfo_h +/* + * Reconstructed from KAME getnameinfo.c (in lib/) + */ + + /* getnameinfo flags */ +#define NI_NOFQDN 0x0001 +#define NI_NUMERICHOST 0x0002 /* return numeric form of address */ +#define NI_NAMEREQD 0x0004 /* request DNS name */ +#define NI_NUMERICSERV 0x0008 +#define NI_DGRAM 0x0010 + +#ifdef __cplusplus +extern "C" { +#endif +/* RFC 2553 / Posix resolver */ +int getnameinfo(const struct sockaddr *sa, + socklen_t salen, + char *host, + size_t hostlen, + char *serv, + size_t servlen, + int flags ); +#ifdef __cplusplus +} +#endif + +#endif /* _getnameinfo_h */ diff --git a/src/3rdparty/squirrel/COPYRIGHT b/src/3rdparty/squirrel/COPYRIGHT new file mode 100644 index 0000000..40b5073 --- /dev/null +++ b/src/3rdparty/squirrel/COPYRIGHT @@ -0,0 +1,29 @@ +Copyright (c) 2003-2011 Alberto Demichelis + +This software is provided 'as-is', without any +express or implied warranty. In no event will the +authors be held liable for any damages arising from +the use of this software. + +Permission is granted to anyone to use this software +for any purpose, including commercial applications, +and to alter it and redistribute it freely, subject +to the following restrictions: + + 1. The origin of this software must not be + misrepresented; you must not claim that + you wrote the original software. If you + use this software in a product, an + acknowledgment in the product + documentation would be appreciated but is + not required. + + 2. Altered source versions must be plainly + marked as such, and must not be + misrepresented as being the original + software. + + 3. This notice may not be removed or + altered from any source distribution. +----------------------------------------------------- +END OF COPYRIGHT diff --git a/src/3rdparty/squirrel/README.OpenTTD b/src/3rdparty/squirrel/README.OpenTTD new file mode 100644 index 0000000..34e4d77 --- /dev/null +++ b/src/3rdparty/squirrel/README.OpenTTD @@ -0,0 +1,4 @@ +This folder contains a modified version of Squirrel that is tailored to meet +the needs of OpenTTD. +We have based this modification on the version as described in: +include/squirrel.h diff --git a/src/3rdparty/squirrel/include/sqstdaux.h b/src/3rdparty/squirrel/include/sqstdaux.h new file mode 100644 index 0000000..ded3c12 --- /dev/null +++ b/src/3rdparty/squirrel/include/sqstdaux.h @@ -0,0 +1,8 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTD_AUXLIB_H_ +#define _SQSTD_AUXLIB_H_ + +void sqstd_seterrorhandlers(HSQUIRRELVM v); +void sqstd_printcallstack(HSQUIRRELVM v); + +#endif /* _SQSTD_AUXLIB_H_ */ diff --git a/src/3rdparty/squirrel/include/sqstdmath.h b/src/3rdparty/squirrel/include/sqstdmath.h new file mode 100644 index 0000000..269a7e4 --- /dev/null +++ b/src/3rdparty/squirrel/include/sqstdmath.h @@ -0,0 +1,7 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTD_MATH_H_ +#define _SQSTD_MATH_H_ + +SQRESULT sqstd_register_mathlib(HSQUIRRELVM v); + +#endif /*_SQSTD_MATH_H_*/ diff --git a/src/3rdparty/squirrel/include/sqstdstring.h b/src/3rdparty/squirrel/include/sqstdstring.h new file mode 100644 index 0000000..856c33f --- /dev/null +++ b/src/3rdparty/squirrel/include/sqstdstring.h @@ -0,0 +1,25 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTD_STRING_H_ +#define _SQSTD_STRING_H_ + +typedef unsigned int SQRexBool; +typedef struct SQRex SQRex; + +typedef struct { + const SQChar *begin; + SQInteger len; +} SQRexMatch; + +SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error); +void sqstd_rex_free(SQRex *exp); +SQBool sqstd_rex_match(SQRex* exp,const SQChar* text); +SQBool sqstd_rex_search(SQRex* exp,const SQChar* text, const SQChar** out_begin, const SQChar** out_end); +SQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* text_end,const SQChar** out_begin, const SQChar** out_end); +SQInteger sqstd_rex_getsubexpcount(SQRex* exp); +SQBool sqstd_rex_getsubexp(SQRex* exp, SQInteger n, SQRexMatch *subexp); + +SQRESULT sqstd_format(HSQUIRRELVM v,SQInteger nformatstringidx,SQInteger *outlen,SQChar **output); + +SQRESULT sqstd_register_stringlib(HSQUIRRELVM v); + +#endif /*_SQSTD_STRING_H_*/ diff --git a/src/3rdparty/squirrel/include/squirrel.h b/src/3rdparty/squirrel/include/squirrel.h new file mode 100644 index 0000000..87e0ac0 --- /dev/null +++ b/src/3rdparty/squirrel/include/squirrel.h @@ -0,0 +1,371 @@ +/* + * Copyright (c) 2003-2011 Alberto Demichelis + * + * This software is provided 'as-is', without any + * express or implied warranty. In no event will the + * authors be held liable for any damages arising from + * the use of this software. + * + * Permission is granted to anyone to use this software + * for any purpose, including commercial applications, + * and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. The origin of this software must not be + * misrepresented; you must not claim that + * you wrote the original software. If you + * use this software in a product, an + * acknowledgment in the product + * documentation would be appreciated but is + * not required. + * + * 2. Altered source versions must be plainly + * marked as such, and must not be + * misrepresented as being the original + * software. + * + * 3. This notice may not be removed or + * altered from any source distribution. + */ +#ifndef _SQUIRREL_H_ +#define _SQUIRREL_H_ + +#include "../../../string_type.h" + +typedef __int64 SQInteger; +typedef unsigned __int64 SQUnsignedInteger; +typedef unsigned __int64 SQHash; /*should be the same size of a pointer*/ +typedef int SQInt32; + + +#ifdef SQUSEDOUBLE +typedef double SQFloat; +#else +typedef float SQFloat; +#endif + +typedef __int64 SQRawObjectVal; //must be 64bits +#define SQ_OBJECT_RAWINIT() { _unVal.raw = 0; } + +typedef void* SQUserPointer; +typedef SQUnsignedInteger SQBool; +typedef SQInteger SQRESULT; + +#define SQTrue (1) +#define SQFalse (0) + +struct SQVM; +struct SQTable; +struct SQArray; +struct SQString; +struct SQClosure; +struct SQGenerator; +struct SQNativeClosure; +struct SQUserData; +struct SQFunctionProto; +struct SQRefCounted; +struct SQClass; +struct SQInstance; +struct SQDelegable; + +typedef char SQChar; +#define MAX_CHAR 0xFFFF + +#define SQUIRREL_VERSION "Squirrel 2.2.5 stable - With custom OpenTTD modifications" +#define SQUIRREL_COPYRIGHT "Copyright (C) 2003-2010 Alberto Demichelis" +#define SQUIRREL_AUTHOR "Alberto Demichelis" +#define SQUIRREL_VERSION_NUMBER 225 + +#define SQ_VMSTATE_IDLE 0 +#define SQ_VMSTATE_RUNNING 1 +#define SQ_VMSTATE_SUSPENDED 2 + +#define SQUIRREL_EOB 0 +#define SQ_BYTECODE_STREAM_TAG 0xFAFA + +#define SQOBJECT_REF_COUNTED 0x08000000 +#define SQOBJECT_NUMERIC 0x04000000 +#define SQOBJECT_DELEGABLE 0x02000000 +#define SQOBJECT_CANBEFALSE 0x01000000 + +#define SQ_MATCHTYPEMASKSTRING (-99999) + +#define _RT_MASK 0x00FFFFFF +#define _RAW_TYPE(type) (type&_RT_MASK) + +#define _RT_NULL 0x00000001 +#define _RT_INTEGER 0x00000002 +#define _RT_FLOAT 0x00000004 +#define _RT_BOOL 0x00000008 +#define _RT_STRING 0x00000010 +#define _RT_TABLE 0x00000020 +#define _RT_ARRAY 0x00000040 +#define _RT_USERDATA 0x00000080 +#define _RT_CLOSURE 0x00000100 +#define _RT_NATIVECLOSURE 0x00000200 +#define _RT_GENERATOR 0x00000400 +#define _RT_USERPOINTER 0x00000800 +#define _RT_THREAD 0x00001000 +#define _RT_FUNCPROTO 0x00002000 +#define _RT_CLASS 0x00004000 +#define _RT_INSTANCE 0x00008000 +#define _RT_WEAKREF 0x00010000 + +typedef enum tagSQObjectType{ + OT_NULL = (_RT_NULL|SQOBJECT_CANBEFALSE), + OT_INTEGER = (_RT_INTEGER|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE), + OT_FLOAT = (_RT_FLOAT|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE), + OT_BOOL = (_RT_BOOL|SQOBJECT_CANBEFALSE), + OT_STRING = (_RT_STRING|SQOBJECT_REF_COUNTED), + OT_TABLE = (_RT_TABLE|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE), + OT_ARRAY = (_RT_ARRAY|SQOBJECT_REF_COUNTED), + OT_USERDATA = (_RT_USERDATA|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE), + OT_CLOSURE = (_RT_CLOSURE|SQOBJECT_REF_COUNTED), + OT_NATIVECLOSURE = (_RT_NATIVECLOSURE|SQOBJECT_REF_COUNTED), + OT_GENERATOR = (_RT_GENERATOR|SQOBJECT_REF_COUNTED), + OT_USERPOINTER = _RT_USERPOINTER, + OT_THREAD = (_RT_THREAD|SQOBJECT_REF_COUNTED) , + OT_FUNCPROTO = (_RT_FUNCPROTO|SQOBJECT_REF_COUNTED), //internal usage only + OT_CLASS = (_RT_CLASS|SQOBJECT_REF_COUNTED), + OT_INSTANCE = (_RT_INSTANCE|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE), + OT_WEAKREF = (_RT_WEAKREF|SQOBJECT_REF_COUNTED) +}SQObjectType; + +#define ISREFCOUNTED(t) (t&SQOBJECT_REF_COUNTED) + + +typedef union tagSQObjectValue +{ + struct SQTable *pTable; + struct SQArray *pArray; + struct SQClosure *pClosure; + struct SQGenerator *pGenerator; + struct SQNativeClosure *pNativeClosure; + struct SQString *pString; + struct SQUserData *pUserData; + SQInteger nInteger; + SQFloat fFloat; + SQUserPointer pUserPointer; + struct SQFunctionProto *pFunctionProto; + struct SQRefCounted *pRefCounted; + struct SQDelegable *pDelegable; + struct SQVM *pThread; + struct SQClass *pClass; + struct SQInstance *pInstance; + struct SQWeakRef *pWeakRef; + SQRawObjectVal raw; +}SQObjectValue; + + +typedef struct tagSQObject +{ + SQObjectType _type; + SQObjectValue _unVal; +}SQObject; + +typedef struct tagSQStackInfos{ + const SQChar* funcname; + const SQChar* source; + SQInteger line; +}SQStackInfos; + +typedef struct SQVM* HSQUIRRELVM; +typedef SQObject HSQOBJECT; +typedef SQInteger (*SQFUNCTION)(HSQUIRRELVM); +typedef SQInteger (*SQRELEASEHOOK)(SQUserPointer,SQInteger size); +typedef void (*SQCOMPILERERROR)(HSQUIRRELVM,const SQChar * /*desc*/,const SQChar * /*source*/,SQInteger /*line*/,SQInteger /*column*/); +typedef void (*SQPRINTFUNCTION)(HSQUIRRELVM,const SQChar * ,...); + +typedef SQInteger (*SQWRITEFUNC)(SQUserPointer,SQUserPointer,SQInteger); +typedef SQInteger (*SQREADFUNC)(SQUserPointer,SQUserPointer,SQInteger); + +typedef WChar (*SQLEXREADFUNC)(SQUserPointer); + +typedef struct tagSQRegFunction{ + const SQChar *name; + SQFUNCTION f; + SQInteger nparamscheck; + const SQChar *typemask; +}SQRegFunction; + +typedef struct tagSQFunctionInfo { + SQUserPointer funcid; + const SQChar *name; + const SQChar *source; +}SQFunctionInfo; + + +/*vm*/ +bool sq_can_suspend(HSQUIRRELVM v); +HSQUIRRELVM sq_open(SQInteger initialstacksize); +HSQUIRRELVM sq_newthread(HSQUIRRELVM friendvm, SQInteger initialstacksize); +void sq_seterrorhandler(HSQUIRRELVM v); +void sq_close(HSQUIRRELVM v); +void sq_setforeignptr(HSQUIRRELVM v,SQUserPointer p); +SQUserPointer sq_getforeignptr(HSQUIRRELVM v); +void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc); +SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v); +SQRESULT sq_suspendvm(HSQUIRRELVM v); +bool sq_resumecatch(HSQUIRRELVM v, int suspend = -1); +bool sq_resumeerror(HSQUIRRELVM v); +SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool resumedret,SQBool retval,SQBool raiseerror,SQBool throwerror); +SQInteger sq_getvmstate(HSQUIRRELVM v); +void sq_decreaseops(HSQUIRRELVM v, int amount); + +/*compiler*/ +SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQChar *sourcename,SQBool raiseerror); +SQRESULT sq_compilebuffer(HSQUIRRELVM v,const SQChar *s,SQInteger size,const SQChar *sourcename,SQBool raiseerror); +void sq_enabledebuginfo(HSQUIRRELVM v, SQBool enable); +void sq_notifyallexceptions(HSQUIRRELVM v, SQBool enable); +void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f); + +/*stack operations*/ +void sq_push(HSQUIRRELVM v,SQInteger idx); +void sq_pop(HSQUIRRELVM v,SQInteger nelemstopop); +void sq_poptop(HSQUIRRELVM v); +void sq_remove(HSQUIRRELVM v,SQInteger idx); +SQInteger sq_gettop(HSQUIRRELVM v); +void sq_settop(HSQUIRRELVM v,SQInteger newtop); +void sq_reservestack(HSQUIRRELVM v,SQInteger nsize); +SQInteger sq_cmp(HSQUIRRELVM v); +void sq_move(HSQUIRRELVM dest,HSQUIRRELVM src,SQInteger idx); + +/*object creation handling*/ +SQUserPointer sq_newuserdata(HSQUIRRELVM v,SQUnsignedInteger size); +void sq_newtable(HSQUIRRELVM v); +void sq_newarray(HSQUIRRELVM v,SQInteger size); +void sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,SQUnsignedInteger nfreevars); +SQRESULT sq_setparamscheck(HSQUIRRELVM v,SQInteger nparamscheck,const SQChar *typemask); +SQRESULT sq_bindenv(HSQUIRRELVM v,SQInteger idx); +void sq_pushstring(HSQUIRRELVM v,const SQChar *s,SQInteger len); +void sq_pushfloat(HSQUIRRELVM v,SQFloat f); +void sq_pushinteger(HSQUIRRELVM v,SQInteger n); +void sq_pushbool(HSQUIRRELVM v,SQBool b); +void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p); +void sq_pushnull(HSQUIRRELVM v); +SQObjectType sq_gettype(HSQUIRRELVM v,SQInteger idx); +SQInteger sq_getsize(HSQUIRRELVM v,SQInteger idx); +SQRESULT sq_getbase(HSQUIRRELVM v,SQInteger idx); +SQBool sq_instanceof(HSQUIRRELVM v); +void sq_tostring(HSQUIRRELVM v,SQInteger idx); +void sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool *b); +SQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,const SQChar **c); +SQRESULT sq_getinteger(HSQUIRRELVM v,SQInteger idx,SQInteger *i); +SQRESULT sq_getfloat(HSQUIRRELVM v,SQInteger idx,SQFloat *f); +SQRESULT sq_getbool(HSQUIRRELVM v,SQInteger idx,SQBool *b); +SQRESULT sq_getthread(HSQUIRRELVM v,SQInteger idx,HSQUIRRELVM *thread); +SQRESULT sq_getuserpointer(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p); +SQRESULT sq_getuserdata(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p,SQUserPointer *typetag); +SQRESULT sq_settypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer typetag); +SQRESULT sq_gettypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer *typetag); +void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook); +SQChar *sq_getscratchpad(HSQUIRRELVM v,SQInteger minsize); +SQRESULT sq_getfunctioninfo(HSQUIRRELVM v,SQInteger idx,SQFunctionInfo *fi); +SQRESULT sq_getclosureinfo(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger *nparams,SQUnsignedInteger *nfreevars); +SQRESULT sq_setnativeclosurename(HSQUIRRELVM v,SQInteger idx,const SQChar *name); +SQRESULT sq_setinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer p); +SQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p,SQUserPointer typetag); +SQRESULT sq_setclassudsize(HSQUIRRELVM v, SQInteger idx, SQInteger udsize); +SQRESULT sq_newclass(HSQUIRRELVM v,SQBool hasbase); +SQRESULT sq_createinstance(HSQUIRRELVM v,SQInteger idx); +SQRESULT sq_setattributes(HSQUIRRELVM v,SQInteger idx); +SQRESULT sq_getattributes(HSQUIRRELVM v,SQInteger idx); +SQRESULT sq_getclass(HSQUIRRELVM v,SQInteger idx); +void sq_weakref(HSQUIRRELVM v,SQInteger idx); +SQRESULT sq_getdefaultdelegate(HSQUIRRELVM v,SQObjectType t); + +/*object manipulation*/ +void sq_pushroottable(HSQUIRRELVM v); +void sq_pushregistrytable(HSQUIRRELVM v); +void sq_pushconsttable(HSQUIRRELVM v); +SQRESULT sq_setroottable(HSQUIRRELVM v); +SQRESULT sq_setconsttable(HSQUIRRELVM v); +SQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx, SQBool bstatic); +SQRESULT sq_deleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval); +SQRESULT sq_set(HSQUIRRELVM v,SQInteger idx); +SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx); +SQRESULT sq_rawget(HSQUIRRELVM v,SQInteger idx); +SQRESULT sq_rawset(HSQUIRRELVM v,SQInteger idx); +SQRESULT sq_rawdeleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval); +SQRESULT sq_arrayappend(HSQUIRRELVM v,SQInteger idx); +SQRESULT sq_arraypop(HSQUIRRELVM v,SQInteger idx,SQBool pushval); +SQRESULT sq_arrayresize(HSQUIRRELVM v,SQInteger idx,SQInteger newsize); +SQRESULT sq_arrayreverse(HSQUIRRELVM v,SQInteger idx); +SQRESULT sq_arrayremove(HSQUIRRELVM v,SQInteger idx,SQInteger itemidx); +SQRESULT sq_arrayinsert(HSQUIRRELVM v,SQInteger idx,SQInteger destpos); +SQRESULT sq_setdelegate(HSQUIRRELVM v,SQInteger idx); +SQRESULT sq_getdelegate(HSQUIRRELVM v,SQInteger idx); +SQRESULT sq_clone(HSQUIRRELVM v,SQInteger idx); +SQRESULT sq_setfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval); +SQRESULT sq_next(HSQUIRRELVM v,SQInteger idx); +SQRESULT sq_getweakrefval(HSQUIRRELVM v,SQInteger idx); +SQRESULT sq_clear(HSQUIRRELVM v,SQInteger idx); + +/*calls*/ +SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool raiseerror, int suspend = -1); +SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror); +const SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx); +const SQChar *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval); +SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err); +void sq_reseterror(HSQUIRRELVM v); +void sq_getlasterror(HSQUIRRELVM v); + +/*raw object handling*/ +SQRESULT sq_getstackobj(HSQUIRRELVM v,SQInteger idx,HSQOBJECT *po); +void sq_pushobject(HSQUIRRELVM v,HSQOBJECT obj); +void sq_addref(HSQUIRRELVM v,HSQOBJECT *po); +SQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po); +void sq_resetobject(HSQOBJECT *po); +const SQChar *sq_objtostring(HSQOBJECT *o); +SQBool sq_objtobool(HSQOBJECT *o); +SQInteger sq_objtointeger(HSQOBJECT *o); +SQFloat sq_objtofloat(HSQOBJECT *o); +SQRESULT sq_getobjtypetag(HSQOBJECT *o,SQUserPointer * typetag); + +/*GC*/ +SQInteger sq_collectgarbage(HSQUIRRELVM v); + +/*serialization*/ +SQRESULT sq_writeclosure(HSQUIRRELVM vm,SQWRITEFUNC writef,SQUserPointer up); +SQRESULT sq_readclosure(HSQUIRRELVM vm,SQREADFUNC readf,SQUserPointer up); + +/*mem allocation*/ +void *sq_malloc(SQUnsignedInteger size); +void *sq_realloc(void* p,SQUnsignedInteger oldsize,SQUnsignedInteger newsize); +void sq_free(void *p,SQUnsignedInteger size); + +/*debug*/ +SQRESULT sq_stackinfos(HSQUIRRELVM v,SQInteger level,SQStackInfos *si); +void sq_setdebughook(HSQUIRRELVM v); + +/*UTILITY MACRO*/ +#define sq_isnumeric(o) ((o)._type&SQOBJECT_NUMERIC) +#define sq_istable(o) ((o)._type==OT_TABLE) +#define sq_isarray(o) ((o)._type==OT_ARRAY) +#define sq_isfunction(o) ((o)._type==OT_FUNCPROTO) +#define sq_isclosure(o) ((o)._type==OT_CLOSURE) +#define sq_isgenerator(o) ((o)._type==OT_GENERATOR) +#define sq_isnativeclosure(o) ((o)._type==OT_NATIVECLOSURE) +#define sq_isstring(o) ((o)._type==OT_STRING) +#define sq_isinteger(o) ((o)._type==OT_INTEGER) +#define sq_isfloat(o) ((o)._type==OT_FLOAT) +#define sq_isuserpointer(o) ((o)._type==OT_USERPOINTER) +#define sq_isuserdata(o) ((o)._type==OT_USERDATA) +#define sq_isthread(o) ((o)._type==OT_THREAD) +#define sq_isnull(o) ((o)._type==OT_NULL) +#define sq_isclass(o) ((o)._type==OT_CLASS) +#define sq_isinstance(o) ((o)._type==OT_INSTANCE) +#define sq_isbool(o) ((o)._type==OT_BOOL) +#define sq_isweakref(o) ((o)._type==OT_WEAKREF) +#define sq_type(o) ((o)._type) + +/* deprecated */ +#define sq_createslot(v,n) sq_newslot(v,n,SQFalse) + +#define SQ_OK (0) +#define SQ_ERROR (-1) + +#define SQ_FAILED(res) (res<0) +#define SQ_SUCCEEDED(res) (res>=0) + +#endif /*_SQUIRREL_H_*/ diff --git a/src/3rdparty/squirrel/sqstdlib/sqstdaux.cpp b/src/3rdparty/squirrel/sqstdlib/sqstdaux.cpp new file mode 100644 index 0000000..67b299b --- /dev/null +++ b/src/3rdparty/squirrel/sqstdlib/sqstdaux.cpp @@ -0,0 +1,146 @@ +/* see copyright notice in squirrel.h */ + +#include "../../../stdafx.h" + +#include +#include + +#include "../../../safeguards.h" + +void sqstd_printcallstack(HSQUIRRELVM v) +{ + SQPRINTFUNCTION pf = sq_getprintfunc(v); + if(pf) { + SQStackInfos si; + SQInteger i; + SQBool b; + SQFloat f; + const SQChar *s; + SQInteger level=1; //1 is to skip this function that is level 0 + const SQChar *name=0; + SQInteger seq=0; + pf(v,"\nCALLSTACK\n"); + while(SQ_SUCCEEDED(sq_stackinfos(v,level,&si))) + { + const SQChar *fn="unknown"; + const SQChar *src="unknown"; + if(si.funcname)fn=si.funcname; + if(si.source) { + /* We don't want to bother users with absolute paths to all AI files. + * Since the path only reaches NoAI code in a formatted string we have + * to strip it here. Let's hope nobody installs openttd in a subdirectory + * of a directory named /ai/. */ + src = strstr(si.source, "\\ai\\"); + if (!src) src = strstr(si.source, "/ai/"); + if (src) { + src += 4; + } else { + src = si.source; + } + } + pf(v,"*FUNCTION [%s()] %s line [%d]\n",fn,src,si.line); + level++; + } + level=0; + pf(v,"\nLOCALS\n"); + + for(level=0;level<10;level++){ + seq=0; + while((name = sq_getlocal(v,level,seq))) + { + seq++; + switch(sq_gettype(v,-1)) + { + case OT_NULL: + pf(v,"[%s] NULL\n",name); + break; + case OT_INTEGER: + sq_getinteger(v,-1,&i); + pf(v,"[%s] %d\n",name,i); + break; + case OT_FLOAT: + sq_getfloat(v,-1,&f); + pf(v,"[%s] %.14g\n",name,f); + break; + case OT_USERPOINTER: + pf(v,"[%s] USERPOINTER\n",name); + break; + case OT_STRING: + sq_getstring(v,-1,&s); + pf(v,"[%s] \"%s\"\n",name,s); + break; + case OT_TABLE: + pf(v,"[%s] TABLE\n",name); + break; + case OT_ARRAY: + pf(v,"[%s] ARRAY\n",name); + break; + case OT_CLOSURE: + pf(v,"[%s] CLOSURE\n",name); + break; + case OT_NATIVECLOSURE: + pf(v,"[%s] NATIVECLOSURE\n",name); + break; + case OT_GENERATOR: + pf(v,"[%s] GENERATOR\n",name); + break; + case OT_USERDATA: + pf(v,"[%s] USERDATA\n",name); + break; + case OT_THREAD: + pf(v,"[%s] THREAD\n",name); + break; + case OT_CLASS: + pf(v,"[%s] CLASS\n",name); + break; + case OT_INSTANCE: + pf(v,"[%s] INSTANCE\n",name); + break; + case OT_WEAKREF: + pf(v,"[%s] WEAKREF\n",name); + break; + case OT_BOOL:{ + sq_getbool(v,-1,&b); + pf(v,"[%s] %s\n",name,b?"true":"false"); + } + break; + default: assert(0); break; + } + sq_pop(v,1); + } + } + } +} + +static SQInteger _sqstd_aux_printerror(HSQUIRRELVM v) +{ + SQPRINTFUNCTION pf = sq_getprintfunc(v); + if(pf) { + const SQChar *sErr = 0; + if(sq_gettop(v)>=1) { + if(SQ_SUCCEEDED(sq_getstring(v,2,&sErr))) { + pf(v,"\nAN ERROR HAS OCCURED [%s]\n",sErr); + } + else{ + pf(v,"\nAN ERROR HAS OCCURED [unknown]\n"); + } + sqstd_printcallstack(v); + } + } + return 0; +} + +void _sqstd_compiler_error(HSQUIRRELVM v,const SQChar *sErr,const SQChar *sSource,SQInteger line,SQInteger column) +{ + SQPRINTFUNCTION pf = sq_getprintfunc(v); + if(pf) { + pf(v,"%s line = (%d) column = (%d) : error %s\n",sSource,line,column,sErr); + } +} + +void sqstd_seterrorhandlers(HSQUIRRELVM v) +{ + sq_setcompilererrorhandler(v,_sqstd_compiler_error); + sq_newclosure(v,_sqstd_aux_printerror,0); + sq_seterrorhandler(v); +} diff --git a/src/3rdparty/squirrel/sqstdlib/sqstdmath.cpp b/src/3rdparty/squirrel/sqstdlib/sqstdmath.cpp new file mode 100644 index 0000000..0ff0090 --- /dev/null +++ b/src/3rdparty/squirrel/sqstdlib/sqstdmath.cpp @@ -0,0 +1,118 @@ +/* see copyright notice in squirrel.h */ + +#include "../../../stdafx.h" + +#include +#include +#include + +#include "../../../safeguards.h" + +#define SINGLE_ARG_FUNC(_funcname, num_ops) static SQInteger math_##_funcname(HSQUIRRELVM v){ \ + SQFloat f; \ + sq_decreaseops(v,num_ops); \ + sq_getfloat(v,2,&f); \ + sq_pushfloat(v,(SQFloat)_funcname(f)); \ + return 1; \ +} + +#define TWO_ARGS_FUNC(_funcname, num_ops) static SQInteger math_##_funcname(HSQUIRRELVM v){ \ + SQFloat p1,p2; \ + sq_decreaseops(v,num_ops); \ + sq_getfloat(v,2,&p1); \ + sq_getfloat(v,3,&p2); \ + sq_pushfloat(v,(SQFloat)_funcname(p1,p2)); \ + return 1; \ +} + +#ifdef EXPORT_DEFAULT_SQUIRREL_FUNCTIONS +static SQInteger math_srand(HSQUIRRELVM v) +{ + SQInteger i; + if(SQ_FAILED(sq_getinteger(v,2,&i))) + return sq_throwerror(v,"invalid param"); + srand((unsigned int)i); + return 0; +} + +static SQInteger math_rand(HSQUIRRELVM v) +{ + sq_pushinteger(v,rand()); + return 1; +} +#endif /* EXPORT_DEFAULT_SQUIRREL_FUNCTIONS */ + +static SQInteger math_abs(HSQUIRRELVM v) +{ + SQInteger n; + sq_getinteger(v,2,&n); + sq_pushinteger(v,(SQInteger)abs((int)n)); + return 1; +} + +SINGLE_ARG_FUNC(sqrt, 100) +SINGLE_ARG_FUNC(fabs, 1) +SINGLE_ARG_FUNC(sin, 100) +SINGLE_ARG_FUNC(cos, 100) +SINGLE_ARG_FUNC(asin, 100) +SINGLE_ARG_FUNC(acos, 100) +SINGLE_ARG_FUNC(log, 100) +SINGLE_ARG_FUNC(log10, 100) +SINGLE_ARG_FUNC(tan, 100) +SINGLE_ARG_FUNC(atan, 100) +TWO_ARGS_FUNC(atan2, 100) +TWO_ARGS_FUNC(pow, 100) +SINGLE_ARG_FUNC(floor, 1) +SINGLE_ARG_FUNC(ceil, 1) +SINGLE_ARG_FUNC(exp, 100) + +#define _DECL_FUNC(name,nparams,tycheck) {#name,math_##name,nparams,tycheck} +static SQRegFunction mathlib_funcs[] = { + _DECL_FUNC(sqrt,2,".n"), + _DECL_FUNC(sin,2,".n"), + _DECL_FUNC(cos,2,".n"), + _DECL_FUNC(asin,2,".n"), + _DECL_FUNC(acos,2,".n"), + _DECL_FUNC(log,2,".n"), + _DECL_FUNC(log10,2,".n"), + _DECL_FUNC(tan,2,".n"), + _DECL_FUNC(atan,2,".n"), + _DECL_FUNC(atan2,3,".nn"), + _DECL_FUNC(pow,3,".nn"), + _DECL_FUNC(floor,2,".n"), + _DECL_FUNC(ceil,2,".n"), + _DECL_FUNC(exp,2,".n"), +#ifdef EXPORT_DEFAULT_SQUIRREL_FUNCTIONS + _DECL_FUNC(srand,2,".n"), + _DECL_FUNC(rand,1,NULL), +#endif /* EXPORT_DEFAULT_SQUIRREL_FUNCTIONS */ + _DECL_FUNC(fabs,2,".n"), + _DECL_FUNC(abs,2,".n"), + {0,0,0,0}, +}; + +#ifndef M_PI +#define M_PI (3.14159265358979323846) +#endif + +SQRESULT sqstd_register_mathlib(HSQUIRRELVM v) +{ + SQInteger i=0; + while(mathlib_funcs[i].name!=0) { + sq_pushstring(v,mathlib_funcs[i].name,-1); + sq_newclosure(v,mathlib_funcs[i].f,0); + sq_setparamscheck(v,mathlib_funcs[i].nparamscheck,mathlib_funcs[i].typemask); + sq_setnativeclosurename(v,-1,mathlib_funcs[i].name); + sq_createslot(v,-3); + i++; + } +#ifdef EXPORT_DEFAULT_SQUIRREL_FUNCTIONS + sq_pushstring(v,"RAND_MAX",-1); + sq_pushinteger(v,RAND_MAX); + sq_createslot(v,-3); +#endif /* EXPORT_DEFAULT_SQUIRREL_FUNCTIONS */ + sq_pushstring(v,"PI",-1); + sq_pushfloat(v,(SQFloat)M_PI); + sq_createslot(v,-3); + return SQ_OK; +} diff --git a/src/3rdparty/squirrel/sqstdlib/sqstdrex.cpp b/src/3rdparty/squirrel/sqstdlib/sqstdrex.cpp new file mode 100644 index 0000000..2bc3684 --- /dev/null +++ b/src/3rdparty/squirrel/sqstdlib/sqstdrex.cpp @@ -0,0 +1,632 @@ +/* see copyright notice in squirrel.h */ +#include +#include +#include "sqstdstring.h" + +#ifdef _UNICODE +#define scisprint iswprint +#else +#define scisprint isprint +#endif + +#ifdef _DEBUG + +static const SQChar *g_nnames[] = +{ + "NONE","OP_GREEDY", "OP_OR", + "OP_EXPR","OP_NOCAPEXPR","OP_DOT", "OP_CLASS", + "OP_CCLASS","OP_NCLASS","OP_RANGE","OP_CHAR", + "OP_EOL","OP_BOL","OP_WB" +}; + +#endif + +#define OP_GREEDY (MAX_CHAR+1) // * + ? {n} +#define OP_OR (MAX_CHAR+2) +#define OP_EXPR (MAX_CHAR+3) //parentesis () +#define OP_NOCAPEXPR (MAX_CHAR+4) //parentesis (?:) +#define OP_DOT (MAX_CHAR+5) +#define OP_CLASS (MAX_CHAR+6) +#define OP_CCLASS (MAX_CHAR+7) +#define OP_NCLASS (MAX_CHAR+8) //negates class the [^ +#define OP_RANGE (MAX_CHAR+9) +#define OP_CHAR (MAX_CHAR+10) +#define OP_EOL (MAX_CHAR+11) +#define OP_BOL (MAX_CHAR+12) +#define OP_WB (MAX_CHAR+13) + +#define SQREX_SYMBOL_ANY_CHAR ('.') +#define SQREX_SYMBOL_GREEDY_ONE_OR_MORE ('+') +#define SQREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*') +#define SQREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?') +#define SQREX_SYMBOL_BRANCH ('|') +#define SQREX_SYMBOL_END_OF_STRING ('$') +#define SQREX_SYMBOL_BEGINNING_OF_STRING ('^') +#define SQREX_SYMBOL_ESCAPE_CHAR ('\\') + + +typedef int SQRexNodeType; + +typedef struct tagSQRexNode{ + SQRexNodeType type; + SQInteger left; + SQInteger right; + SQInteger next; +}SQRexNode; + +struct SQRex{ + const SQChar *_eol; + const SQChar *_bol; + const SQChar *_p; + SQInteger _first; + SQInteger _op; + SQRexNode *_nodes; + SQInteger _nallocated; + SQInteger _nsize; + SQInteger _nsubexpr; + SQRexMatch *_matches; + SQInteger _currsubexp; + const SQChar **_error; +}; + +static SQInteger sqstd_rex_list(SQRex *exp); + +static SQInteger sqstd_rex_newnode(SQRex *exp, SQRexNodeType type) +{ + SQRexNode n; + n.type = type; + n.next = n.right = n.left = -1; + if(type == OP_EXPR) + n.right = exp->_nsubexpr++; + if(exp->_nallocated < (exp->_nsize + 1)) { + SQInteger oldsize = exp->_nallocated; + exp->_nallocated *= 2; + exp->_nodes = (SQRexNode *)sq_realloc(exp->_nodes, oldsize * sizeof(SQRexNode) ,exp->_nallocated * sizeof(SQRexNode)); + } + exp->_nodes[exp->_nsize++] = n; + SQInteger newid = exp->_nsize - 1; + return (SQInteger)newid; +} + +static void sqstd_rex_error(SQRex *exp,const SQChar *error) +{ + if(exp->_error) *exp->_error = error; + throw std::exception(); +} + +static void sqstd_rex_expect(SQRex *exp, SQChar n){ + if((*exp->_p) != n) + sqstd_rex_error(exp, "expected paren"); + exp->_p++; +} + +static SQChar sqstd_rex_escapechar(SQRex *exp) +{ + if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR){ + exp->_p++; + switch(*exp->_p) { + case 'v': exp->_p++; return '\v'; + case 'n': exp->_p++; return '\n'; + case 't': exp->_p++; return '\t'; + case 'r': exp->_p++; return '\r'; + case 'f': exp->_p++; return '\f'; + default: return (*exp->_p++); + } + } else if(!scisprint(*exp->_p)) sqstd_rex_error(exp,"letter expected"); + return (*exp->_p++); +} + +static SQInteger sqstd_rex_charclass(SQRex *exp,SQInteger classid) +{ + SQInteger n = sqstd_rex_newnode(exp,OP_CCLASS); + exp->_nodes[n].left = classid; + return n; +} + +static SQInteger sqstd_rex_charnode(SQRex *exp,SQBool isclass) +{ + SQChar t; + if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR) { + exp->_p++; + switch(*exp->_p) { + case 'n': exp->_p++; return sqstd_rex_newnode(exp,'\n'); + case 't': exp->_p++; return sqstd_rex_newnode(exp,'\t'); + case 'r': exp->_p++; return sqstd_rex_newnode(exp,'\r'); + case 'f': exp->_p++; return sqstd_rex_newnode(exp,'\f'); + case 'v': exp->_p++; return sqstd_rex_newnode(exp,'\v'); + case 'a': case 'A': case 'w': case 'W': case 's': case 'S': + case 'd': case 'D': case 'x': case 'X': case 'c': case 'C': + case 'p': case 'P': case 'l': case 'u': + { + t = *exp->_p; exp->_p++; + return sqstd_rex_charclass(exp,t); + } + case 'b': + case 'B': + if(!isclass) { + SQInteger node = sqstd_rex_newnode(exp,OP_WB); + exp->_nodes[node].left = *exp->_p; + exp->_p++; + return node; + } //else default + default: + t = *exp->_p; exp->_p++; + return sqstd_rex_newnode(exp,t); + } + } + else if(!scisprint(*exp->_p)) { + + sqstd_rex_error(exp,"letter expected"); + } + t = *exp->_p; exp->_p++; + return sqstd_rex_newnode(exp,t); +} +static SQInteger sqstd_rex_class(SQRex *exp) +{ + SQInteger ret = -1; + SQInteger first = -1,chain; + if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING){ + ret = sqstd_rex_newnode(exp,OP_NCLASS); + exp->_p++; + }else ret = sqstd_rex_newnode(exp,OP_CLASS); + + if(*exp->_p == ']') sqstd_rex_error(exp,"empty class"); + chain = ret; + while(*exp->_p != ']' && exp->_p != exp->_eol) { + if(*exp->_p == '-' && first != -1){ + SQInteger r; + if(*exp->_p++ == ']') sqstd_rex_error(exp,"unfinished range"); + r = sqstd_rex_newnode(exp,OP_RANGE); + if(exp->_nodes[first].type>*exp->_p) sqstd_rex_error(exp,"invalid range"); + if(exp->_nodes[first].type == OP_CCLASS) sqstd_rex_error(exp,"cannot use character classes in ranges"); + exp->_nodes[r].left = exp->_nodes[first].type; + SQInteger t = sqstd_rex_escapechar(exp); + exp->_nodes[r].right = t; + exp->_nodes[chain].next = r; + chain = r; + first = -1; + } + else{ + if(first!=-1){ + SQInteger c = first; + exp->_nodes[chain].next = c; + chain = c; + first = sqstd_rex_charnode(exp,SQTrue); + } + else{ + first = sqstd_rex_charnode(exp,SQTrue); + } + } + } + if(first!=-1){ + SQInteger c = first; + exp->_nodes[chain].next = c; + chain = c; + first = -1; + } + /* hack? */ + exp->_nodes[ret].left = exp->_nodes[ret].next; + exp->_nodes[ret].next = -1; + return ret; +} + +static SQInteger sqstd_rex_parsenumber(SQRex *exp) +{ + SQInteger ret = *exp->_p-'0'; + SQInteger positions = 10; + exp->_p++; + while(isdigit(*exp->_p)) { + ret = ret*10+(*exp->_p++-'0'); + if(positions==1000000000) sqstd_rex_error(exp,"overflow in numeric constant"); + positions *= 10; + }; + return ret; +} + +static SQInteger sqstd_rex_element(SQRex *exp) +{ + SQInteger ret = -1; + switch(*exp->_p) + { + case '(': { + SQInteger expr; + exp->_p++; + + + if(*exp->_p =='?') { + exp->_p++; + sqstd_rex_expect(exp,':'); + expr = sqstd_rex_newnode(exp,OP_NOCAPEXPR); + } + else + expr = sqstd_rex_newnode(exp,OP_EXPR); + SQInteger newn = sqstd_rex_list(exp); + exp->_nodes[expr].left = newn; + ret = expr; + sqstd_rex_expect(exp,')'); + } + break; + case '[': + exp->_p++; + ret = sqstd_rex_class(exp); + sqstd_rex_expect(exp,']'); + break; + case SQREX_SYMBOL_END_OF_STRING: exp->_p++; ret = sqstd_rex_newnode(exp,OP_EOL);break; + case SQREX_SYMBOL_ANY_CHAR: exp->_p++; ret = sqstd_rex_newnode(exp,OP_DOT);break; + default: + ret = sqstd_rex_charnode(exp,SQFalse); + break; + } + + + SQInteger op; + SQBool isgreedy = SQFalse; + unsigned short p0 = 0, p1 = 0; + switch(*exp->_p){ + case SQREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; isgreedy = SQTrue; break; + case SQREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; isgreedy = SQTrue; break; + case SQREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; isgreedy = SQTrue; break; + case '{': + exp->_p++; + if(!isdigit(*exp->_p)) sqstd_rex_error(exp,"number expected"); + p0 = (unsigned short)sqstd_rex_parsenumber(exp); + /*******************************/ + switch(*exp->_p) { + case '}': + p1 = p0; exp->_p++; + break; + case ',': + exp->_p++; + p1 = 0xFFFF; + if(isdigit(*exp->_p)){ + p1 = (unsigned short)sqstd_rex_parsenumber(exp); + } + sqstd_rex_expect(exp,'}'); + break; + default: + sqstd_rex_error(exp,", or } expected"); + } + /*******************************/ + isgreedy = SQTrue; + break; + + } + if(isgreedy) { + SQInteger nnode = sqstd_rex_newnode(exp,OP_GREEDY); + op = OP_GREEDY; + exp->_nodes[nnode].left = ret; + exp->_nodes[nnode].right = ((p0)<<16)|p1; + ret = nnode; + } + + if((*exp->_p != SQREX_SYMBOL_BRANCH) && (*exp->_p != ')') && (*exp->_p != SQREX_SYMBOL_GREEDY_ZERO_OR_MORE) && (*exp->_p != SQREX_SYMBOL_GREEDY_ONE_OR_MORE) && (*exp->_p != '\0')) { + SQInteger nnode = sqstd_rex_element(exp); + exp->_nodes[ret].next = nnode; + } + + return ret; +} + +static SQInteger sqstd_rex_list(SQRex *exp) +{ + SQInteger ret=-1,e; + if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING) { + exp->_p++; + ret = sqstd_rex_newnode(exp,OP_BOL); + } + e = sqstd_rex_element(exp); + if(ret != -1) { + exp->_nodes[ret].next = e; + } + else ret = e; + + if(*exp->_p == SQREX_SYMBOL_BRANCH) { + SQInteger temp,tright; + exp->_p++; + temp = sqstd_rex_newnode(exp,OP_OR); + exp->_nodes[temp].left = ret; + tright = sqstd_rex_list(exp); + exp->_nodes[temp].right = tright; + ret = temp; + } + return ret; +} + +static SQBool sqstd_rex_matchcclass(SQInteger cclass,SQChar c) +{ + switch(cclass) { + case 'a': return isalpha(c)?SQTrue:SQFalse; + case 'A': return !isalpha(c)?SQTrue:SQFalse; + case 'w': return (isalnum(c) || c == '_')?SQTrue:SQFalse; + case 'W': return (!isalnum(c) && c != '_')?SQTrue:SQFalse; + case 's': return isspace(c)?SQTrue:SQFalse; + case 'S': return !isspace(c)?SQTrue:SQFalse; + case 'd': return isdigit(c)?SQTrue:SQFalse; + case 'D': return !isdigit(c)?SQTrue:SQFalse; + case 'x': return isxdigit(c)?SQTrue:SQFalse; + case 'X': return !isxdigit(c)?SQTrue:SQFalse; + case 'c': return iscntrl(c)?SQTrue:SQFalse; + case 'C': return !iscntrl(c)?SQTrue:SQFalse; + case 'p': return ispunct(c)?SQTrue:SQFalse; + case 'P': return !ispunct(c)?SQTrue:SQFalse; + case 'l': return islower(c)?SQTrue:SQFalse; + case 'u': return isupper(c)?SQTrue:SQFalse; + } + return SQFalse; /*cannot happen*/ +} + +static SQBool sqstd_rex_matchclass(SQRex* exp,SQRexNode *node,SQInteger c) +{ + do { + switch(node->type) { + case OP_RANGE: + if(c >= node->left && c <= node->right) return SQTrue; + break; + case OP_CCLASS: + if(sqstd_rex_matchcclass(node->left,c)) return SQTrue; + break; + default: + if(c == node->type)return SQTrue; + } + } while((node->next != -1) && (node = &exp->_nodes[node->next])); + return SQFalse; +} + +static const SQChar *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const SQChar *str,SQRexNode *next) +{ + + SQRexNodeType type = node->type; + switch(type) { + case OP_GREEDY: { + //SQRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL; + SQRexNode *greedystop = NULL; + SQInteger p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0; + const SQChar *s=str, *good = str; + + if(node->next != -1) { + greedystop = &exp->_nodes[node->next]; + } + else { + greedystop = next; + } + + while((nmaches == 0xFFFF || nmaches < p1)) { + + const SQChar *stop; + if(!(s = sqstd_rex_matchnode(exp,&exp->_nodes[node->left],s,greedystop))) + break; + nmaches++; + good=s; + if(greedystop) { + //checks that 0 matches satisfy the expression(if so skips) + //if not would always stop(for instance if is a '?') + if(greedystop->type != OP_GREEDY || + (greedystop->type == OP_GREEDY && ((greedystop->right >> 16)&0x0000FFFF) != 0)) + { + SQRexNode *gnext = NULL; + if(greedystop->next != -1) { + gnext = &exp->_nodes[greedystop->next]; + }else if(next && next->next != -1){ + gnext = &exp->_nodes[next->next]; + } + stop = sqstd_rex_matchnode(exp,greedystop,s,gnext); + if(stop) { + //if satisfied stop it + if(p0 == p1 && p0 == nmaches) break; + else if(nmaches >= p0 && p1 == 0xFFFF) break; + else if(nmaches >= p0 && nmaches <= p1) break; + } + } + } + + if(s >= exp->_eol) + break; + } + if(p0 == p1 && p0 == nmaches) return good; + else if(nmaches >= p0 && p1 == 0xFFFF) return good; + else if(nmaches >= p0 && nmaches <= p1) return good; + return NULL; + } + case OP_OR: { + const SQChar *asd = str; + SQRexNode *temp=&exp->_nodes[node->left]; + while( (asd = sqstd_rex_matchnode(exp,temp,asd,NULL)) ) { + if(temp->next != -1) + temp = &exp->_nodes[temp->next]; + else + return asd; + } + asd = str; + temp = &exp->_nodes[node->right]; + while( (asd = sqstd_rex_matchnode(exp,temp,asd,NULL)) ) { + if(temp->next != -1) + temp = &exp->_nodes[temp->next]; + else + return asd; + } + return NULL; + break; + } + case OP_EXPR: + case OP_NOCAPEXPR:{ + SQRexNode *n = &exp->_nodes[node->left]; + const SQChar *cur = str; + SQInteger capture = -1; + if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) { + capture = exp->_currsubexp; + exp->_matches[capture].begin = cur; + exp->_currsubexp++; + } + + do { + SQRexNode *subnext = NULL; + if(n->next != -1) { + subnext = &exp->_nodes[n->next]; + }else { + subnext = next; + } + if(!(cur = sqstd_rex_matchnode(exp,n,cur,subnext))) { + if(capture != -1){ + exp->_matches[capture].begin = 0; + exp->_matches[capture].len = 0; + } + return NULL; + } + } while((n->next != -1) && (n = &exp->_nodes[n->next])); + + if(capture != -1) + exp->_matches[capture].len = cur - exp->_matches[capture].begin; + return cur; + } + case OP_WB: + if((str == exp->_bol && !isspace(*str)) + || (str == exp->_eol && !isspace(*(str-1))) + || (!isspace(*str) && isspace(*(str+1))) + || (isspace(*str) && !isspace(*(str+1))) ) { + return (node->left == 'b')?str:NULL; + } + return (node->left == 'b')?NULL:str; + case OP_BOL: + if(str == exp->_bol) return str; + return NULL; + case OP_EOL: + if(str == exp->_eol) return str; + return NULL; + case OP_DOT:{ + *str++; + } + return str; + case OP_NCLASS: + case OP_CLASS: + if(sqstd_rex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?SQTrue:SQFalse):(type == OP_NCLASS?SQTrue:SQFalse)) { + *str++; + return str; + } + return NULL; + case OP_CCLASS: + if(sqstd_rex_matchcclass(node->left,*str)) { + *str++; + return str; + } + return NULL; + default: /* char */ + if(*str != (SQChar)node->type) return NULL; + *str++; + return str; + } + return NULL; +} + +/* public api */ +SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error) +{ + SQRex *exp = (SQRex *)sq_malloc(sizeof(SQRex)); + exp->_eol = exp->_bol = NULL; + exp->_p = pattern; + exp->_nallocated = (SQInteger)strlen(pattern) * sizeof(SQChar); + exp->_nodes = (SQRexNode *)sq_malloc(exp->_nallocated * sizeof(SQRexNode)); + exp->_nsize = 0; + exp->_matches = 0; + exp->_nsubexpr = 0; + exp->_first = sqstd_rex_newnode(exp,OP_EXPR); + exp->_error = error; + try { + SQInteger res = sqstd_rex_list(exp); + exp->_nodes[exp->_first].left = res; + if(*exp->_p!='\0') + sqstd_rex_error(exp,"unexpected character"); +#ifdef _DEBUG + { + SQInteger nsize,i; + SQRexNode *t; + nsize = exp->_nsize; + t = &exp->_nodes[0]; + printf("\n"); + /* XXX -- The (int) casts are needed to silent warnings on 64bit systems (SQInteger is 64bit, %d assumes 32bit, (int) is 32bit) */ + for(i = 0;i < nsize; i++) { + if(exp->_nodes[i].type>MAX_CHAR) + printf("[%02d] %10s ",(int)i,g_nnames[exp->_nodes[i].type-MAX_CHAR]); + else + printf("[%02d] %10c ",(int)i,exp->_nodes[i].type); + printf("left %02d right %02d next %02d\n",(int)exp->_nodes[i].left,(int)exp->_nodes[i].right,(int)exp->_nodes[i].next); + } + printf("\n"); + } +#endif + exp->_matches = (SQRexMatch *) sq_malloc(exp->_nsubexpr * sizeof(SQRexMatch)); + memset(exp->_matches,0,exp->_nsubexpr * sizeof(SQRexMatch)); + } + catch (...) { + sqstd_rex_free(exp); + return NULL; + } + return exp; +} + +void sqstd_rex_free(SQRex *exp) +{ + if(exp) { + if(exp->_nodes) sq_free(exp->_nodes,exp->_nallocated * sizeof(SQRexNode)); + if(exp->_matches) sq_free(exp->_matches,exp->_nsubexpr * sizeof(SQRexMatch)); + sq_free(exp,sizeof(SQRex)); + } +} + +SQBool sqstd_rex_match(SQRex* exp,const SQChar* text) +{ + const SQChar* res = NULL; + exp->_bol = text; + exp->_eol = text + strlen(text); + exp->_currsubexp = 0; + res = sqstd_rex_matchnode(exp,exp->_nodes,text,NULL); + if(res == NULL || res != exp->_eol) + return SQFalse; + return SQTrue; +} + +SQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* text_end,const SQChar** out_begin, const SQChar** out_end) +{ + const SQChar *cur = NULL; + SQInteger node = exp->_first; + if(text_begin >= text_end) return SQFalse; + exp->_bol = text_begin; + exp->_eol = text_end; + do { + cur = text_begin; + while(node != -1) { + exp->_currsubexp = 0; + cur = sqstd_rex_matchnode(exp,&exp->_nodes[node],cur,NULL); + if(!cur) + break; + node = exp->_nodes[node].next; + } + *text_begin++; + } while(cur == NULL && text_begin != text_end); + + if(cur == NULL) + return SQFalse; + + --text_begin; + + if(out_begin) *out_begin = text_begin; + if(out_end) *out_end = cur; + return SQTrue; +} + +SQBool sqstd_rex_search(SQRex* exp,const SQChar* text, const SQChar** out_begin, const SQChar** out_end) +{ + return sqstd_rex_searchrange(exp,text,text + strlen(text),out_begin,out_end); +} + +SQInteger sqstd_rex_getsubexpcount(SQRex* exp) +{ + return exp->_nsubexpr; +} + +SQBool sqstd_rex_getsubexp(SQRex* exp, SQInteger n, SQRexMatch *subexp) +{ + if( n<0 || n >= exp->_nsubexpr) return SQFalse; + *subexp = exp->_matches[n]; + return SQTrue; +} + diff --git a/src/3rdparty/squirrel/sqstdlib/sqstdstring.cpp b/src/3rdparty/squirrel/sqstdlib/sqstdstring.cpp new file mode 100644 index 0000000..8639b64 --- /dev/null +++ b/src/3rdparty/squirrel/sqstdlib/sqstdstring.cpp @@ -0,0 +1,366 @@ +/* see copyright notice in squirrel.h */ +#include +#include +#include + +#define scstrchr strchr +#define scatoi atoi +#define scstrtok strtok +#define MAX_FORMAT_LEN 20 +#define MAX_WFORMAT_LEN 3 +#define ADDITIONAL_FORMAT_SPACE (100*sizeof(SQChar)) + +static SQInteger validate_format(HSQUIRRELVM v, SQChar *fmt, const SQChar *src, SQInteger n,SQInteger &width) +{ + SQChar swidth[MAX_WFORMAT_LEN]; + SQInteger wc = 0; + SQInteger start = n; + fmt[0] = '%'; + while (scstrchr("-+ #0", src[n])) n++; + while (isdigit(src[n])) { + swidth[wc] = src[n]; + n++; + wc++; + if(wc>=MAX_WFORMAT_LEN) + return sq_throwerror(v,"width format too long"); + } + swidth[wc] = '\0'; + if(wc > 0) { + width = atoi(swidth); + } + else + width = 0; + if (src[n] == '.') { + n++; + + wc = 0; + while (isdigit(src[n])) { + swidth[wc] = src[n]; + n++; + wc++; + if(wc>=MAX_WFORMAT_LEN) + return sq_throwerror(v,"precision format too long"); + } + swidth[wc] = '\0'; + if(wc > 0) { + width += atoi(swidth); + } + } + if (n-start > MAX_FORMAT_LEN ) + return sq_throwerror(v,"format too long"); + memcpy(&fmt[1],&src[start],((n-start)+1)*sizeof(SQChar)); + fmt[(n-start)+2] = '\0'; + return n; +} + +/* + * Little hack to remove the "format not a string literal, argument types not checked" warning. + * This check has been added to OpenTTD to make sure that nobody passes wrong string literals, + * but three lines in Squirrel have a little problem with those. Therefor we use this hack + * which basically uses vsnprintf instead of sprintf as vsnprintf is not testing for the right + * string literal at compile time. + */ +static void _append_string(SQInteger &i, SQChar *dest, SQInteger allocated, const SQChar *fmt, ...) +{ + va_list va; + va_start(va, fmt); + i += vsnprintf(&dest[i],allocated-i,fmt,va); + va_end(va); +} + + +SQRESULT sqstd_format(HSQUIRRELVM v,SQInteger nformatstringidx,SQInteger *outlen,SQChar **output) +{ + const SQChar *format; + SQChar *dest; + SQChar fmt[MAX_FORMAT_LEN]; + sq_getstring(v,nformatstringidx,&format); + SQInteger allocated = (sq_getsize(v,nformatstringidx)+2)*sizeof(SQChar); + dest = sq_getscratchpad(v,allocated); + SQInteger n = 0,i = 0, nparam = nformatstringidx+1, w = 0; + while(format[n] != '\0') { + if(format[n] != '%') { + assert(i < allocated); + dest[i++] = format[n]; + n++; + } + else if(format[n+1] == '%') { //handles %% + dest[i++] = '%'; + n += 2; + } + else { + n++; + if( nparam > sq_gettop(v) ) + return sq_throwerror(v,"not enough paramters for the given format string"); + n = validate_format(v,fmt,format,n,w); + if(n < 0) return -1; + SQInteger addlen = 0; + SQInteger valtype = 0; + const SQChar *ts; + SQInteger ti; + SQFloat tf; + switch(format[n]) { + case 's': + if(SQ_FAILED(sq_getstring(v,nparam,&ts))) + return sq_throwerror(v,"string expected for the specified format"); + addlen = (sq_getsize(v,nparam)*sizeof(SQChar))+((w+1)*sizeof(SQChar)); + valtype = 's'; + break; + case 'i': case 'd': case 'c':case 'o': case 'u': case 'x': case 'X': + if(SQ_FAILED(sq_getinteger(v,nparam,&ti))) + return sq_throwerror(v,"integer expected for the specified format"); + addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(SQChar)); + valtype = 'i'; + break; + case 'f': case 'g': case 'G': case 'e': case 'E': + if(SQ_FAILED(sq_getfloat(v,nparam,&tf))) + return sq_throwerror(v,"float expected for the specified format"); + addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(SQChar)); + valtype = 'f'; + break; + default: + return sq_throwerror(v,"invalid format"); + } + n++; + allocated += addlen + sizeof(SQChar); + dest = sq_getscratchpad(v,allocated); + switch(valtype) { + case 's': _append_string(i,dest,allocated,fmt,ts); break; + case 'i': _append_string(i,dest,allocated,fmt,ti); break; + case 'f': _append_string(i,dest,allocated,fmt,tf); break; + }; + nparam ++; + } + } + *outlen = i; + dest[i] = '\0'; + *output = dest; + return SQ_OK; +} + +static SQInteger _string_format(HSQUIRRELVM v) +{ + SQChar *dest = NULL; + SQInteger length = 0; + if(SQ_FAILED(sqstd_format(v,2,&length,&dest))) + return -1; + sq_pushstring(v,dest,length); + return 1; +} + +static void __strip_l(const SQChar *str,const SQChar **start) +{ + const SQChar *t = str; + while(((*t) != '\0') && isspace(*t)){ t++; } + *start = t; +} + +static void __strip_r(const SQChar *str,SQInteger len,const SQChar **end) +{ + if(len == 0) { + *end = str; + return; + } + const SQChar *t = &str[len-1]; + while(t != str && isspace(*t)) { t--; } + *end = t+1; +} + +static SQInteger _string_strip(HSQUIRRELVM v) +{ + const SQChar *str,*start,*end; + sq_getstring(v,2,&str); + SQInteger len = sq_getsize(v,2); + __strip_l(str,&start); + __strip_r(str,len,&end); + sq_pushstring(v,start,end - start); + return 1; +} + +static SQInteger _string_lstrip(HSQUIRRELVM v) +{ + const SQChar *str,*start; + sq_getstring(v,2,&str); + __strip_l(str,&start); + sq_pushstring(v,start,-1); + return 1; +} + +static SQInteger _string_rstrip(HSQUIRRELVM v) +{ + const SQChar *str,*end; + sq_getstring(v,2,&str); + SQInteger len = sq_getsize(v,2); + __strip_r(str,len,&end); + sq_pushstring(v,str,end - str); + return 1; +} + +static SQInteger _string_split(HSQUIRRELVM v) +{ + const SQChar *str,*seps; + SQChar *stemp,*tok; + sq_getstring(v,2,&str); + sq_getstring(v,3,&seps); + if(sq_getsize(v,3) == 0) return sq_throwerror(v,"empty separators string"); + SQInteger memsize = (sq_getsize(v,2)+1)*sizeof(SQChar); + stemp = sq_getscratchpad(v,memsize); + memcpy(stemp,str,memsize); + tok = scstrtok(stemp,seps); + sq_newarray(v,0); + while( tok != NULL ) { + sq_pushstring(v,tok,-1); + sq_arrayappend(v,-2); + tok = scstrtok( NULL, seps ); + } + return 1; +} + +#define SETUP_REX(v) \ + SQRex *self = NULL; \ + sq_getinstanceup(v,1,(SQUserPointer *)&self,0); + +static SQInteger _rexobj_releasehook(SQUserPointer p, SQInteger size) +{ + SQRex *self = ((SQRex *)p); + sqstd_rex_free(self); + return 1; +} + +static SQInteger _regexp_match(HSQUIRRELVM v) +{ + SETUP_REX(v); + const SQChar *str; + sq_getstring(v,2,&str); + if(sqstd_rex_match(self,str) == SQTrue) + { + sq_pushbool(v,SQTrue); + return 1; + } + sq_pushbool(v,SQFalse); + return 1; +} + +static void _addrexmatch(HSQUIRRELVM v,const SQChar *str,const SQChar *begin,const SQChar *end) +{ + sq_newtable(v); + sq_pushstring(v,"begin",-1); + sq_pushinteger(v,begin - str); + sq_rawset(v,-3); + sq_pushstring(v,"end",-1); + sq_pushinteger(v,end - str); + sq_rawset(v,-3); +} + +static SQInteger _regexp_search(HSQUIRRELVM v) +{ + SETUP_REX(v); + const SQChar *str,*begin,*end; + SQInteger start = 0; + sq_getstring(v,2,&str); + if(sq_gettop(v) > 2) sq_getinteger(v,3,&start); + if(sqstd_rex_search(self,str+start,&begin,&end) == SQTrue) { + _addrexmatch(v,str,begin,end); + return 1; + } + return 0; +} + +static SQInteger _regexp_capture(HSQUIRRELVM v) +{ + SETUP_REX(v); + const SQChar *str,*begin,*end; + SQInteger start = 0; + sq_getstring(v,2,&str); + if(sq_gettop(v) > 2) sq_getinteger(v,3,&start); + if(sqstd_rex_search(self,str+start,&begin,&end) == SQTrue) { + SQInteger n = sqstd_rex_getsubexpcount(self); + SQRexMatch match; + sq_newarray(v,0); + for(SQInteger i = 0;i < n; i++) { + sqstd_rex_getsubexp(self,i,&match); + if(match.len > 0) + _addrexmatch(v,str,match.begin,match.begin+match.len); + else + _addrexmatch(v,str,str,str); //empty match + sq_arrayappend(v,-2); + } + return 1; + } + return 0; +} + +static SQInteger _regexp_subexpcount(HSQUIRRELVM v) +{ + SETUP_REX(v); + sq_pushinteger(v,sqstd_rex_getsubexpcount(self)); + return 1; +} + +static SQInteger _regexp_constructor(HSQUIRRELVM v) +{ + const SQChar *error,*pattern; + sq_getstring(v,2,&pattern); + SQRex *rex = sqstd_rex_compile(pattern,&error); + if(!rex) return sq_throwerror(v,error); + sq_setinstanceup(v,1,rex); + sq_setreleasehook(v,1,_rexobj_releasehook); + return 0; +} + +static SQInteger _regexp__typeof(HSQUIRRELVM v) +{ + sq_pushstring(v,"regexp",-1); + return 1; +} + +#define _DECL_REX_FUNC(name,nparams,pmask) {#name,_regexp_##name,nparams,pmask} +static SQRegFunction rexobj_funcs[]={ + _DECL_REX_FUNC(constructor,2,".s"), + _DECL_REX_FUNC(search,-2,"xsn"), + _DECL_REX_FUNC(match,2,"xs"), + _DECL_REX_FUNC(capture,-2,"xsn"), + _DECL_REX_FUNC(subexpcount,1,"x"), + _DECL_REX_FUNC(_typeof,1,"x"), + {0,0,0,0} +}; + +#define _DECL_FUNC(name,nparams,pmask) {#name,_string_##name,nparams,pmask} +static SQRegFunction stringlib_funcs[]={ + _DECL_FUNC(format,-2,".s"), + _DECL_FUNC(strip,2,".s"), + _DECL_FUNC(lstrip,2,".s"), + _DECL_FUNC(rstrip,2,".s"), + _DECL_FUNC(split,3,".ss"), + {0,0,0,0} +}; + + +SQInteger sqstd_register_stringlib(HSQUIRRELVM v) +{ + sq_pushstring(v,"regexp",-1); + sq_newclass(v,SQFalse); + SQInteger i = 0; + while(rexobj_funcs[i].name != 0) { + SQRegFunction &f = rexobj_funcs[i]; + sq_pushstring(v,f.name,-1); + sq_newclosure(v,f.f,0); + sq_setparamscheck(v,f.nparamscheck,f.typemask); + sq_setnativeclosurename(v,-1,f.name); + sq_createslot(v,-3); + i++; + } + sq_createslot(v,-3); + + i = 0; + while(stringlib_funcs[i].name!=0) + { + sq_pushstring(v,stringlib_funcs[i].name,-1); + sq_newclosure(v,stringlib_funcs[i].f,0); + sq_setparamscheck(v,stringlib_funcs[i].nparamscheck,stringlib_funcs[i].typemask); + sq_setnativeclosurename(v,-1,stringlib_funcs[i].name); + sq_createslot(v,-3); + i++; + } + return 1; +} diff --git a/src/3rdparty/squirrel/squirrel/sqapi.cpp b/src/3rdparty/squirrel/squirrel/sqapi.cpp new file mode 100644 index 0000000..f02fee2 --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqapi.cpp @@ -0,0 +1,1325 @@ +/* + * see copyright notice in squirrel.h + */ + +#include "../../../stdafx.h" + +#include +#include "sqpcheader.h" +#include "sqvm.h" +#include "sqstring.h" +#include "sqtable.h" +#include "sqarray.h" +#include "sqfuncproto.h" +#include "sqclosure.h" +#include "squserdata.h" +#include "sqcompiler.h" +#include "sqfuncstate.h" +#include "sqclass.h" + +#include "../../../string_func.h" + +#include "../../../safeguards.h" + +bool sq_aux_gettypedarg(HSQUIRRELVM v,SQInteger idx,SQObjectType type,SQObjectPtr **o) +{ + *o = &stack_get(v,idx); + if(type(**o) != type){ + SQObjectPtr oval = v->PrintObjVal(**o); + v->Raise_Error("wrong argument type, expected '%s' got '%.50s'",IdType2Name(type),_stringval(oval)); + return false; + } + return true; +} + +#define _GETSAFE_OBJ(v,idx,type,o) { if(!sq_aux_gettypedarg(v,idx,type,&o)) return SQ_ERROR; } + +#define sq_aux_paramscheck(v,count) \ +{ \ + if(sq_gettop(v) < count){ v->Raise_Error("not enough params in the stack"); return SQ_ERROR; }\ +} + +SQInteger sq_aux_throwobject(HSQUIRRELVM v,SQObjectPtr &e) +{ + v->_lasterror = e; + return SQ_ERROR; +} + +SQInteger sq_aux_invalidtype(HSQUIRRELVM v,SQObjectType type) +{ + char buf[100]; + seprintf(buf, lastof(buf), "unexpected type %s", IdType2Name(type)); + return sq_throwerror(v, buf); +} + +HSQUIRRELVM sq_open(SQInteger initialstacksize) +{ + SQSharedState *ss; + SQVM *v; + sq_new(ss, SQSharedState); + v = (SQVM *)SQ_MALLOC(sizeof(SQVM)); + new (v) SQVM(ss); + ss->_root_vm = v; + if(v->Init(NULL, initialstacksize)) { + return v; + } else { + sq_delete(v, SQVM); + return NULL; + } + return v; +} + +HSQUIRRELVM sq_newthread(HSQUIRRELVM friendvm, SQInteger initialstacksize) +{ + SQSharedState *ss; + SQVM *v; + ss=_ss(friendvm); + + v= (SQVM *)SQ_MALLOC(sizeof(SQVM)); + new (v) SQVM(ss); + + if(v->Init(friendvm, initialstacksize)) { + friendvm->Push(v); + return v; + } else { + sq_delete(v, SQVM); + return NULL; + } +} + +SQInteger sq_getvmstate(HSQUIRRELVM v) +{ + if(v->_suspended) + return SQ_VMSTATE_SUSPENDED; + else { + if(v->_callsstacksize != 0) return SQ_VMSTATE_RUNNING; + else return SQ_VMSTATE_IDLE; + } +} + +void sq_decreaseops(HSQUIRRELVM v, int amount) +{ + v->DecreaseOps(amount); +} + +bool sq_can_suspend(HSQUIRRELVM v) +{ + return v->_nnativecalls <= 2; +} + +void sq_seterrorhandler(HSQUIRRELVM v) +{ + SQObject o = stack_get(v, -1); + if(sq_isclosure(o) || sq_isnativeclosure(o) || sq_isnull(o)) { + v->_errorhandler = o; + v->Pop(); + } +} + +void sq_setdebughook(HSQUIRRELVM v) +{ + SQObject o = stack_get(v,-1); + if(sq_isclosure(o) || sq_isnativeclosure(o) || sq_isnull(o)) { + v->_debughook = o; + v->Pop(); + } +} + +void sq_close(HSQUIRRELVM v) +{ + SQSharedState *ss = _ss(v); + _thread(ss->_root_vm)->Finalize(); + sq_delete(ss, SQSharedState); +} + +SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQChar *sourcename,SQBool raiseerror) +{ + SQObjectPtr o; + if(Compile(v, read, p, sourcename, o, raiseerror?true:false, _ss(v)->_debuginfo)) { + v->Push(SQClosure::Create(_ss(v), _funcproto(o))); + return SQ_OK; + } + return SQ_ERROR; +} + +void sq_enabledebuginfo(HSQUIRRELVM v, SQBool enable) +{ + _ss(v)->_debuginfo = enable?true:false; +} + +void sq_notifyallexceptions(HSQUIRRELVM v, SQBool enable) +{ + _ss(v)->_notifyallexceptions = enable?true:false; +} + +void sq_addref(HSQUIRRELVM v,HSQOBJECT *po) +{ + if(!ISREFCOUNTED(type(*po))) return; +#ifdef NO_GARBAGE_COLLECTOR + __AddRef(po->_type,po->_unVal); +#else + _ss(v)->_refs_table.AddRef(*po); +#endif +} + +SQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po) +{ + if(!ISREFCOUNTED(type(*po))) return SQTrue; +#ifdef NO_GARBAGE_COLLECTOR + __Release(po->_type,po->_unVal); + return SQFalse; //the ret val doesn't work(and cannot be fixed) +#else + return _ss(v)->_refs_table.Release(*po); +#endif +} + +const SQChar *sq_objtostring(HSQOBJECT *o) +{ + if(sq_type(*o) == OT_STRING) { + return _stringval(*o); + } + return NULL; +} + +SQInteger sq_objtointeger(HSQOBJECT *o) +{ + if(sq_isnumeric(*o)) { + return tointeger(*o); + } + return 0; +} + +SQFloat sq_objtofloat(HSQOBJECT *o) +{ + if(sq_isnumeric(*o)) { + return tofloat(*o); + } + return 0; +} + +SQBool sq_objtobool(HSQOBJECT *o) +{ + if(sq_isbool(*o)) { + return _integer(*o); + } + return SQFalse; +} + +void sq_pushnull(HSQUIRRELVM v) +{ + v->Push(_null_); +} + +void sq_pushstring(HSQUIRRELVM v,const SQChar *s,SQInteger len) +{ + if(s) + v->Push(SQObjectPtr(SQString::Create(_ss(v), s, len))); + else v->Push(_null_); +} + +void sq_pushinteger(HSQUIRRELVM v,SQInteger n) +{ + v->Push(n); +} + +void sq_pushbool(HSQUIRRELVM v,SQBool b) +{ + v->Push(b?true:false); +} + +void sq_pushfloat(HSQUIRRELVM v,SQFloat n) +{ + v->Push(n); +} + +void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p) +{ + v->Push(p); +} + +SQUserPointer sq_newuserdata(HSQUIRRELVM v,SQUnsignedInteger size) +{ + SQUserData *ud = SQUserData::Create(_ss(v), size); + v->Push(ud); + return ud->_val; +} + +void sq_newtable(HSQUIRRELVM v) +{ + v->Push(SQTable::Create(_ss(v), 0)); +} + +void sq_newarray(HSQUIRRELVM v,SQInteger size) +{ + v->Push(SQArray::Create(_ss(v), size)); +} + +SQRESULT sq_newclass(HSQUIRRELVM v,SQBool hasbase) +{ + SQClass *baseclass = NULL; + if(hasbase) { + SQObjectPtr &base = stack_get(v,-1); + if(type(base) != OT_CLASS) + return sq_throwerror(v,"invalid base type"); + baseclass = _class(base); + } + SQClass *newclass = SQClass::Create(_ss(v), baseclass); + if(baseclass) v->Pop(); + v->Push(newclass); + return SQ_OK; +} + +SQBool sq_instanceof(HSQUIRRELVM v) +{ + SQObjectPtr &inst = stack_get(v,-1); + SQObjectPtr &cl = stack_get(v,-2); + if(type(inst) != OT_INSTANCE || type(cl) != OT_CLASS) + return sq_throwerror(v,"invalid param type"); + return _instance(inst)->InstanceOf(_class(cl))?SQTrue:SQFalse; +} + +SQRESULT sq_arrayappend(HSQUIRRELVM v,SQInteger idx) +{ + sq_aux_paramscheck(v,2); + SQObjectPtr *arr; + _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); + _array(*arr)->Append(v->GetUp(-1)); + v->Pop(1); + return SQ_OK; +} + +SQRESULT sq_arraypop(HSQUIRRELVM v,SQInteger idx,SQBool pushval) +{ + sq_aux_paramscheck(v, 1); + SQObjectPtr *arr; + _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); + if(_array(*arr)->Size() > 0) { + if(pushval != 0){ v->Push(_array(*arr)->Top()); } + _array(*arr)->Pop(); + return SQ_OK; + } + return sq_throwerror(v, "empty array"); +} + +SQRESULT sq_arrayresize(HSQUIRRELVM v,SQInteger idx,SQInteger newsize) +{ + sq_aux_paramscheck(v,1); + SQObjectPtr *arr; + _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); + if(newsize >= 0) { + _array(*arr)->Resize(newsize); + return SQ_OK; + } + return sq_throwerror(v,"negative size"); +} + + +SQRESULT sq_arrayreverse(HSQUIRRELVM v,SQInteger idx) +{ + sq_aux_paramscheck(v, 1); + SQObjectPtr *o; + _GETSAFE_OBJ(v, idx, OT_ARRAY,o); + SQArray *arr = _array(*o); + if(arr->Size() > 0) { + SQObjectPtr t; + SQInteger size = arr->Size(); + SQInteger n = size >> 1; size -= 1; + for(SQInteger i = 0; i < n; i++) { + t = arr->_values[i]; + arr->_values[i] = arr->_values[size-i]; + arr->_values[size-i] = t; + } + return SQ_OK; + } + return SQ_OK; +} + +SQRESULT sq_arrayremove(HSQUIRRELVM v,SQInteger idx,SQInteger itemidx) +{ + sq_aux_paramscheck(v, 1); + SQObjectPtr *arr; + _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); + return _array(*arr)->Remove(itemidx) ? SQ_OK : sq_throwerror(v,"index out of range"); +} + +SQRESULT sq_arrayinsert(HSQUIRRELVM v,SQInteger idx,SQInteger destpos) +{ + sq_aux_paramscheck(v, 1); + SQObjectPtr *arr; + _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); + SQRESULT ret = _array(*arr)->Insert(destpos, v->GetUp(-1)) ? SQ_OK : sq_throwerror(v,"index out of range"); + v->Pop(); + return ret; +} + + +void sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,SQUnsignedInteger nfreevars) +{ + SQNativeClosure *nc = SQNativeClosure::Create(_ss(v), func); + for(SQUnsignedInteger i = 0; i < nfreevars; i++) { + nc->_outervalues.push_back(v->Top()); + v->Pop(); + } + v->Push(SQObjectPtr(nc)); +} + +SQRESULT sq_getclosureinfo(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger *nparams,SQUnsignedInteger *nfreevars) +{ + SQObject o = stack_get(v, idx); + if(sq_isclosure(o)) { + SQClosure *c = _closure(o); + SQFunctionProto *proto = _funcproto(c->_function); + *nparams = (SQUnsignedInteger)proto->_nparameters; + *nfreevars = (SQUnsignedInteger)c->_outervalues.size(); + return SQ_OK; + } + return sq_throwerror(v,"the object is not a closure"); +} + +SQRESULT sq_setnativeclosurename(HSQUIRRELVM v,SQInteger idx,const SQChar *name) +{ + SQObject o = stack_get(v, idx); + if(sq_isnativeclosure(o)) { + SQNativeClosure *nc = _nativeclosure(o); + nc->_name = SQString::Create(_ss(v),name); + return SQ_OK; + } + return sq_throwerror(v,"the object is not a nativeclosure"); +} + +SQRESULT sq_setparamscheck(HSQUIRRELVM v,SQInteger nparamscheck,const SQChar *typemask) +{ + SQObject o = stack_get(v, -1); + if(!sq_isnativeclosure(o)) + return sq_throwerror(v, "native closure expected"); + SQNativeClosure *nc = _nativeclosure(o); + nc->_nparamscheck = nparamscheck; + if(typemask) { + SQIntVec res; + if(!CompileTypemask(res, typemask)) + return sq_throwerror(v, "invalid typemask"); + nc->_typecheck.copy(res); + } + else { + nc->_typecheck.resize(0); + } + if(nparamscheck == SQ_MATCHTYPEMASKSTRING) { + nc->_nparamscheck = nc->_typecheck.size(); + } + return SQ_OK; +} + +SQRESULT sq_bindenv(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &o = stack_get(v,idx); + if(!sq_isnativeclosure(o) && + !sq_isclosure(o)) + return sq_throwerror(v,"the target is not a closure"); + SQObjectPtr &env = stack_get(v,-1); + if(!sq_istable(env) && + !sq_isclass(env) && + !sq_isinstance(env)) + return sq_throwerror(v,"invalid environment"); + SQObjectPtr w = _refcounted(env)->GetWeakRef(type(env)); + SQObjectPtr ret; + if(sq_isclosure(o)) { + SQClosure *c = _closure(o)->Clone(); + c->_env = w; + ret = c; + } + else { //then must be a native closure + SQNativeClosure *c = _nativeclosure(o)->Clone(); + c->_env = w; + ret = c; + } + v->Pop(); + v->Push(ret); + return SQ_OK; +} + +SQRESULT sq_clear(HSQUIRRELVM v,SQInteger idx) +{ + SQObject &o=stack_get(v,idx); + switch(type(o)) { + case OT_TABLE: _table(o)->Clear(); break; + case OT_ARRAY: _array(o)->Resize(0); break; + default: + return sq_throwerror(v, "clear only works on table and array"); + break; + + } + return SQ_OK; +} + +void sq_pushroottable(HSQUIRRELVM v) +{ + v->Push(v->_roottable); +} + +void sq_pushregistrytable(HSQUIRRELVM v) +{ + v->Push(_ss(v)->_registry); +} + +void sq_pushconsttable(HSQUIRRELVM v) +{ + v->Push(_ss(v)->_consts); +} + +SQRESULT sq_setroottable(HSQUIRRELVM v) +{ + SQObject o = stack_get(v, -1); + if(sq_istable(o) || sq_isnull(o)) { + v->_roottable = o; + v->Pop(); + return SQ_OK; + } + return sq_throwerror(v, "ivalid type"); +} + +SQRESULT sq_setconsttable(HSQUIRRELVM v) +{ + SQObject o = stack_get(v, -1); + if(sq_istable(o)) { + _ss(v)->_consts = o; + v->Pop(); + return SQ_OK; + } + return sq_throwerror(v, "ivalid type, expected table"); +} + +void sq_setforeignptr(HSQUIRRELVM v,SQUserPointer p) +{ + v->_foreignptr = p; +} + +SQUserPointer sq_getforeignptr(HSQUIRRELVM v) +{ + return v->_foreignptr; +} + +void sq_push(HSQUIRRELVM v,SQInteger idx) +{ + v->Push(stack_get(v, idx)); +} + +SQObjectType sq_gettype(HSQUIRRELVM v,SQInteger idx) +{ + return type(stack_get(v, idx)); +} + + +void sq_tostring(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &o = stack_get(v, idx); + SQObjectPtr res; + v->ToString(o,res); + v->Push(res); +} + +void sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool *b) +{ + SQObjectPtr &o = stack_get(v, idx); + *b = v->IsFalse(o)?SQFalse:SQTrue; +} + +SQRESULT sq_getinteger(HSQUIRRELVM v,SQInteger idx,SQInteger *i) +{ + SQObjectPtr &o = stack_get(v, idx); + if(sq_isnumeric(o)) { + *i = tointeger(o); + return SQ_OK; + } + return SQ_ERROR; +} + +SQRESULT sq_getfloat(HSQUIRRELVM v,SQInteger idx,SQFloat *f) +{ + SQObjectPtr &o = stack_get(v, idx); + if(sq_isnumeric(o)) { + *f = tofloat(o); + return SQ_OK; + } + return SQ_ERROR; +} + +SQRESULT sq_getbool(HSQUIRRELVM v,SQInteger idx,SQBool *b) +{ + SQObjectPtr &o = stack_get(v, idx); + if(sq_isbool(o)) { + *b = _integer(o); + return SQ_OK; + } + return SQ_ERROR; +} + +SQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,const SQChar **c) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_STRING,o); + *c = _stringval(*o); + return SQ_OK; +} + +SQRESULT sq_getthread(HSQUIRRELVM v,SQInteger idx,HSQUIRRELVM *thread) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_THREAD,o); + *thread = _thread(*o); + return SQ_OK; +} + +SQRESULT sq_clone(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &o = stack_get(v,idx); + v->Push(_null_); + if(!v->Clone(o, stack_get(v, -1))){ + v->Pop(); + return sq_aux_invalidtype(v, type(o)); + } + return SQ_OK; +} + +SQInteger sq_getsize(HSQUIRRELVM v, SQInteger idx) +{ + SQObjectPtr &o = stack_get(v, idx); + SQObjectType type = type(o); + switch(type) { + case OT_STRING: return _string(o)->_len; + case OT_TABLE: return _table(o)->CountUsed(); + case OT_ARRAY: return _array(o)->Size(); + case OT_USERDATA: return _userdata(o)->_size; + case OT_INSTANCE: return _instance(o)->_class->_udsize; + case OT_CLASS: return _class(o)->_udsize; + default: + return sq_aux_invalidtype(v, type); + } +} + +SQRESULT sq_getuserdata(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p,SQUserPointer *typetag) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_USERDATA,o); + (*p) = _userdataval(*o); + if(typetag) *typetag = _userdata(*o)->_typetag; + return SQ_OK; +} + +SQRESULT sq_settypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer typetag) +{ + SQObjectPtr &o = stack_get(v,idx); + switch(type(o)) { + case OT_USERDATA: _userdata(o)->_typetag = typetag; break; + case OT_CLASS: _class(o)->_typetag = typetag; break; + default: return sq_throwerror(v,"invalid object type"); + } + return SQ_OK; +} + +SQRESULT sq_getobjtypetag(HSQOBJECT *o,SQUserPointer * typetag) +{ + switch(type(*o)) { + case OT_INSTANCE: *typetag = _instance(*o)->_class->_typetag; break; + case OT_USERDATA: *typetag = _userdata(*o)->_typetag; break; + case OT_CLASS: *typetag = _class(*o)->_typetag; break; + default: return SQ_ERROR; + } + return SQ_OK; +} + +SQRESULT sq_gettypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer *typetag) +{ + SQObjectPtr &o = stack_get(v,idx); + if(SQ_FAILED(sq_getobjtypetag(&o,typetag))) + return sq_throwerror(v,"invalid object type"); + return SQ_OK; +} + +SQRESULT sq_getuserpointer(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_USERPOINTER,o); + (*p) = _userpointer(*o); + return SQ_OK; +} + +SQRESULT sq_setinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer p) +{ + SQObjectPtr &o = stack_get(v,idx); + if(type(o) != OT_INSTANCE) return sq_throwerror(v,"the object is not a class instance"); + _instance(o)->_userpointer = p; + return SQ_OK; +} + +SQRESULT sq_setclassudsize(HSQUIRRELVM v, SQInteger idx, SQInteger udsize) +{ + SQObjectPtr &o = stack_get(v,idx); + if(type(o) != OT_CLASS) return sq_throwerror(v,"the object is not a class"); + if(_class(o)->_locked) return sq_throwerror(v,"the class is locked"); + _class(o)->_udsize = udsize; + return SQ_OK; +} + + +SQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p,SQUserPointer typetag) +{ + SQObjectPtr &o = stack_get(v,idx); + if(type(o) != OT_INSTANCE) return sq_throwerror(v,"the object is not a class instance"); + (*p) = _instance(o)->_userpointer; + if(typetag != 0) { + SQClass *cl = _instance(o)->_class; + do{ + if(cl->_typetag == typetag) + return SQ_OK; + cl = cl->_base; + }while(cl != NULL); + return sq_throwerror(v,"invalid type tag"); + } + return SQ_OK; +} + +SQInteger sq_gettop(HSQUIRRELVM v) +{ + return (v->_top) - v->_stackbase; +} + +void sq_settop(HSQUIRRELVM v, SQInteger newtop) +{ + SQInteger top = sq_gettop(v); + if(top > newtop) + sq_pop(v, top - newtop); + else + while(top++ < newtop) sq_pushnull(v); +} + +void sq_pop(HSQUIRRELVM v, SQInteger nelemstopop) +{ + assert(v->_top >= nelemstopop); + v->Pop(nelemstopop); +} + +void sq_poptop(HSQUIRRELVM v) +{ + assert(v->_top >= 1); + v->Pop(); +} + + +void sq_remove(HSQUIRRELVM v, SQInteger idx) +{ + v->Remove(idx); +} + +SQInteger sq_cmp(HSQUIRRELVM v) +{ + SQInteger res; + v->ObjCmp(stack_get(v, -1), stack_get(v, -2),res); + return res; +} + +SQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx, SQBool bstatic) +{ + sq_aux_paramscheck(v, 3); + SQObjectPtr &self = stack_get(v, idx); + if(type(self) == OT_TABLE || type(self) == OT_CLASS) { + SQObjectPtr &key = v->GetUp(-2); + if(type(key) == OT_NULL) return sq_throwerror(v, "null is not a valid key"); + v->NewSlot(self, key, v->GetUp(-1),bstatic?true:false); + v->Pop(2); + } + return SQ_OK; +} + +SQRESULT sq_deleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval) +{ + sq_aux_paramscheck(v, 2); + SQObjectPtr *self; + _GETSAFE_OBJ(v, idx, OT_TABLE,self); + SQObjectPtr &key = v->GetUp(-1); + if(type(key) == OT_NULL) return sq_throwerror(v, "null is not a valid key"); + SQObjectPtr res; + if(!v->DeleteSlot(*self, key, res)){ + return SQ_ERROR; + } + if(pushval) v->GetUp(-1) = res; + else v->Pop(1); + return SQ_OK; +} + +SQRESULT sq_set(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &self = stack_get(v, idx); + if(v->Set(self, v->GetUp(-2), v->GetUp(-1),false)) { + v->Pop(2); + return SQ_OK; + } + v->Raise_IdxError(v->GetUp(-2));return SQ_ERROR; +} + +SQRESULT sq_rawset(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &self = stack_get(v, idx); + if(type(v->GetUp(-2)) == OT_NULL) return sq_throwerror(v, "null key"); + switch(type(self)) { + case OT_TABLE: + _table(self)->NewSlot(v->GetUp(-2), v->GetUp(-1)); + v->Pop(2); + return SQ_OK; + break; + case OT_CLASS: + _class(self)->NewSlot(_ss(v), v->GetUp(-2), v->GetUp(-1),false); + v->Pop(2); + return SQ_OK; + break; + case OT_INSTANCE: + if(_instance(self)->Set(v->GetUp(-2), v->GetUp(-1))) { + v->Pop(2); + return SQ_OK; + } + break; + case OT_ARRAY: + if(v->Set(self, v->GetUp(-2), v->GetUp(-1),false)) { + v->Pop(2); + return SQ_OK; + } + break; + default: + v->Pop(2); + return sq_throwerror(v, "rawset works only on array/table/class and instance"); + } + v->Raise_IdxError(v->GetUp(-2));return SQ_ERROR; +} + +SQRESULT sq_setdelegate(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &self = stack_get(v, idx); + SQObjectPtr &mt = v->GetUp(-1); + SQObjectType type = type(self); + switch(type) { + case OT_TABLE: + if(type(mt) == OT_TABLE) { + if(!_table(self)->SetDelegate(_table(mt))) return sq_throwerror(v, "delagate cycle"); v->Pop();} + else if(type(mt)==OT_NULL) { + _table(self)->SetDelegate(NULL); v->Pop(); } + else return sq_aux_invalidtype(v,type); + break; + case OT_USERDATA: + if(type(mt)==OT_TABLE) { + _userdata(self)->SetDelegate(_table(mt)); v->Pop(); } + else if(type(mt)==OT_NULL) { + _userdata(self)->SetDelegate(NULL); v->Pop(); } + else return sq_aux_invalidtype(v, type); + break; + default: + return sq_aux_invalidtype(v, type); + break; + } + return SQ_OK; +} + +SQRESULT sq_rawdeleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval) +{ + sq_aux_paramscheck(v, 2); + SQObjectPtr *self; + _GETSAFE_OBJ(v, idx, OT_TABLE,self); + SQObjectPtr &key = v->GetUp(-1); + SQObjectPtr t; + if(_table(*self)->Get(key,t)) { + _table(*self)->Remove(key); + } + if(pushval != 0) { + if(pushval) v->GetUp(-1) = t; + } else { + v->Pop(1); + } + return SQ_OK; +} + +SQRESULT sq_getdelegate(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &self=stack_get(v,idx); + switch(type(self)){ + case OT_TABLE: + case OT_USERDATA: + if(!_delegable(self)->_delegate){ + v->Push(_null_); + break; + } + v->Push(SQObjectPtr(_delegable(self)->_delegate)); + break; + default: return sq_throwerror(v,"wrong type"); break; + } + return SQ_OK; + +} + +SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &self=stack_get(v,idx); + if(v->Get(self,v->GetUp(-1),v->GetUp(-1),false,false)) + return SQ_OK; + v->Pop(1); + return sq_throwerror(v,"the index doesn't exist"); +} + +SQRESULT sq_rawget(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &self=stack_get(v,idx); + switch(type(self)) { + case OT_TABLE: + if(_table(self)->Get(v->GetUp(-1),v->GetUp(-1))) + return SQ_OK; + break; + case OT_CLASS: + if(_class(self)->Get(v->GetUp(-1),v->GetUp(-1))) + return SQ_OK; + break; + case OT_INSTANCE: + if(_instance(self)->Get(v->GetUp(-1),v->GetUp(-1))) + return SQ_OK; + break; + case OT_ARRAY: + if(v->Get(self,v->GetUp(-1),v->GetUp(-1),false,false)) + return SQ_OK; + break; + default: + v->Pop(1); + return sq_throwerror(v,"rawget works only on array/table/instance and class"); + } + v->Pop(1); + return sq_throwerror(v,"the index doesn't exist"); +} + +SQRESULT sq_getstackobj(HSQUIRRELVM v,SQInteger idx,HSQOBJECT *po) +{ + *po=stack_get(v,idx); + return SQ_OK; +} + +const SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx) +{ + SQUnsignedInteger cstksize=v->_callsstacksize; + SQUnsignedInteger lvl=(cstksize-level)-1; + SQInteger stackbase=v->_stackbase; + if(lvl_callsstack[(cstksize-i)-1]; + stackbase-=ci._prevstkbase; + } + SQVM::CallInfo &ci=v->_callsstack[lvl]; + if(type(ci._closure)!=OT_CLOSURE) + return NULL; + SQClosure *c=_closure(ci._closure); + SQFunctionProto *func=_funcproto(c->_function); + if(func->_noutervalues > (SQInteger)idx) { + v->Push(c->_outervalues[idx]); + return _stringval(func->_outervalues[idx]._name); + } + idx -= func->_noutervalues; + return func->GetLocal(v,stackbase,idx,(SQInteger)(ci._ip-func->_instructions)-1); + } + return NULL; +} + +void sq_pushobject(HSQUIRRELVM v,HSQOBJECT obj) +{ + v->Push(SQObjectPtr(obj)); +} + +void sq_resetobject(HSQOBJECT *po) +{ + po->_unVal.pUserPointer=NULL;po->_type=OT_NULL; +} + +SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err) +{ + v->_lasterror=SQString::Create(_ss(v),err); + return -1; +} + +void sq_reseterror(HSQUIRRELVM v) +{ + v->_lasterror = _null_; +} + +void sq_getlasterror(HSQUIRRELVM v) +{ + v->Push(v->_lasterror); +} + +void sq_reservestack(HSQUIRRELVM v,SQInteger nsize) +{ + if (((SQUnsignedInteger)v->_top + nsize) > v->_stack.size()) { + v->_stack.resize(v->_stack.size() + ((v->_top + nsize) - v->_stack.size())); + } +} + +SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror) +{ + if(type(v->GetUp(-1))==OT_GENERATOR){ + v->Push(_null_); //retval + v->_can_suspend = false; + if(!v->Execute(v->GetUp(-2),v->_top,0,v->_top,v->GetUp(-1),raiseerror,SQVM::ET_RESUME_GENERATOR)) + {v->Raise_Error(v->_lasterror); return SQ_ERROR;} + if(!retval) + v->Pop(); + return SQ_OK; + } + return sq_throwerror(v,"only generators can be resumed"); +} + +SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool raiseerror, int suspend) +{ + SQObjectPtr res; + v->_can_suspend = suspend >= 0; + if (v->_can_suspend) v->_ops_till_suspend = suspend; + + if(v->Call(v->GetUp(-(params+1)),params,v->_top-params,res,raiseerror?true:false,v->_can_suspend)){ + if(!v->_suspended) { + v->Pop(params);//pop closure and args + } + if(retval){ + v->Push(res); return SQ_OK; + } + return SQ_OK; + } + else { + v->Pop(params); + return SQ_ERROR; + } +} + +SQRESULT sq_suspendvm(HSQUIRRELVM v) +{ + return v->Suspend(); +} + +SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool wakeupret,SQBool retval,SQBool raiseerror,SQBool throwerror) +{ + SQObjectPtr ret; + if(!v->_suspended) + return sq_throwerror(v,"cannot resume a vm that is not running any code"); + if(wakeupret) { + v->GetAt(v->_stackbase+v->_suspended_target)=v->GetUp(-1); //retval + v->Pop(); + } else v->GetAt(v->_stackbase+v->_suspended_target)=_null_; + v->_can_suspend = false; + if(!v->Execute(_null_,v->_top,-1,-1,ret,raiseerror,throwerror?SQVM::ET_RESUME_THROW_VM : SQVM::ET_RESUME_VM)) + return SQ_ERROR; + if(sq_getvmstate(v) == SQ_VMSTATE_IDLE) { + while (v->_top > 1) v->_stack[--v->_top] = _null_; + } + if(retval) + v->Push(ret); + return SQ_OK; +} + +bool sq_resumecatch(HSQUIRRELVM v, int suspend) +{ + SQObjectPtr ret; + v->_can_suspend = suspend >= 0; + if (v->_can_suspend) v->_ops_till_suspend = suspend; + return v->Execute(_null_, v->_top, -1, -1, ret, SQTrue, SQVM::ET_RESUME_OPENTTD); +} + +bool sq_resumeerror(HSQUIRRELVM v) +{ + SQObjectPtr ret; + v->_can_suspend = true; + v->_ops_till_suspend = 1; + return v->Execute(_null_, v->_top, -1, -1, ret, SQTrue, SQVM::ET_RESUME_THROW_VM); +} + +void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook) +{ + if(sq_gettop(v) >= 1){ + SQObjectPtr &ud=stack_get(v,idx); + switch( type(ud) ) { + case OT_USERDATA: _userdata(ud)->_hook = hook; break; + case OT_INSTANCE: _instance(ud)->_hook = hook; break; + case OT_CLASS: _class(ud)->_hook = hook; break; + default: break; //shutup compiler + } + } +} + +void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f) +{ + _ss(v)->_compilererrorhandler = f; +} + +SQRESULT sq_writeclosure(HSQUIRRELVM v,SQWRITEFUNC w,SQUserPointer up) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, -1, OT_CLOSURE,o); + unsigned short tag = SQ_BYTECODE_STREAM_TAG; + if(w(up,&tag,2) != 2) + return sq_throwerror(v,"io error"); + if(!_closure(*o)->Save(v,up,w)) + return SQ_ERROR; + return SQ_OK; +} + +SQRESULT sq_readclosure(HSQUIRRELVM v,SQREADFUNC r,SQUserPointer up) +{ + SQObjectPtr closure; + + unsigned short tag; + if(r(up,&tag,2) != 2) + return sq_throwerror(v,"io error"); + if(tag != SQ_BYTECODE_STREAM_TAG) + return sq_throwerror(v,"invalid stream"); + if(!SQClosure::Load(v,up,r,closure)) + return SQ_ERROR; + v->Push(closure); + return SQ_OK; +} + +SQChar *sq_getscratchpad(HSQUIRRELVM v,SQInteger minsize) +{ + return _ss(v)->GetScratchPad(minsize); +} + +SQInteger sq_collectgarbage(HSQUIRRELVM v) +{ +#ifndef NO_GARBAGE_COLLECTOR + return _ss(v)->CollectGarbage(v); +#else + return -1; +#endif +} + +const SQChar *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval) +{ + SQObjectPtr &self = stack_get(v,idx); + const SQChar *name = NULL; + if(type(self) == OT_CLOSURE) { + if(_closure(self)->_outervalues.size()>nval) { + v->Push(_closure(self)->_outervalues[nval]); + SQFunctionProto *fp = _funcproto(_closure(self)->_function); + SQOuterVar &ov = fp->_outervalues[nval]; + name = _stringval(ov._name); + } + } + return name; +} + +SQRESULT sq_setfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval) +{ + SQObjectPtr &self=stack_get(v,idx); + switch(type(self)) + { + case OT_CLOSURE: + if(_closure(self)->_outervalues.size()>nval){ + _closure(self)->_outervalues[nval]=stack_get(v,-1); + } + else return sq_throwerror(v,"invalid free var index"); + break; + case OT_NATIVECLOSURE: + if(_nativeclosure(self)->_outervalues.size()>nval){ + _nativeclosure(self)->_outervalues[nval]=stack_get(v,-1); + } + else return sq_throwerror(v,"invalid free var index"); + break; + default: + return sq_aux_invalidtype(v,type(self)); + } + v->Pop(1); + return SQ_OK; +} + +SQRESULT sq_setattributes(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_CLASS,o); + SQObjectPtr &key = stack_get(v,-2); + SQObjectPtr &val = stack_get(v,-1); + SQObjectPtr attrs; + if(type(key) == OT_NULL) { + attrs = _class(*o)->_attributes; + _class(*o)->_attributes = val; + v->Pop(2); + v->Push(attrs); + return SQ_OK; + }else if(_class(*o)->GetAttributes(key,attrs)) { + _class(*o)->SetAttributes(key,val); + v->Pop(2); + v->Push(attrs); + return SQ_OK; + } + return sq_throwerror(v,"wrong index"); +} + +SQRESULT sq_getattributes(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_CLASS,o); + SQObjectPtr &key = stack_get(v,-1); + SQObjectPtr attrs; + if(type(key) == OT_NULL) { + attrs = _class(*o)->_attributes; + v->Pop(); + v->Push(attrs); + return SQ_OK; + } + else if(_class(*o)->GetAttributes(key,attrs)) { + v->Pop(); + v->Push(attrs); + return SQ_OK; + } + return sq_throwerror(v,"wrong index"); +} + +SQRESULT sq_getbase(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_CLASS,o); + if(_class(*o)->_base) + v->Push(SQObjectPtr(_class(*o)->_base)); + else + v->Push(_null_); + return SQ_OK; +} + +SQRESULT sq_getclass(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_INSTANCE,o); + v->Push(SQObjectPtr(_instance(*o)->_class)); + return SQ_OK; +} + +SQRESULT sq_createinstance(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr *o = NULL; + _GETSAFE_OBJ(v, idx, OT_CLASS,o); + v->Push(_class(*o)->CreateInstance()); + return SQ_OK; +} + +void sq_weakref(HSQUIRRELVM v,SQInteger idx) +{ + SQObject &o=stack_get(v,idx); + if(ISREFCOUNTED(type(o))) { + v->Push(_refcounted(o)->GetWeakRef(type(o))); + return; + } + v->Push(o); +} + +SQRESULT sq_getweakrefval(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr &o = stack_get(v,idx); + if(type(o) != OT_WEAKREF) { + return sq_throwerror(v,"the object must be a weakref"); + } + v->Push(_weakref(o)->_obj); + return SQ_OK; +} + +SQRESULT sq_getdefaultdelegate(HSQUIRRELVM v,SQObjectType t) +{ + SQSharedState *ss = _ss(v); + switch(t) { + case OT_TABLE: v->Push(ss->_table_default_delegate); break; + case OT_ARRAY: v->Push(ss->_array_default_delegate); break; + case OT_STRING: v->Push(ss->_string_default_delegate); break; + case OT_INTEGER: case OT_FLOAT: v->Push(ss->_number_default_delegate); break; + case OT_GENERATOR: v->Push(ss->_generator_default_delegate); break; + case OT_CLOSURE: case OT_NATIVECLOSURE: v->Push(ss->_closure_default_delegate); break; + case OT_THREAD: v->Push(ss->_thread_default_delegate); break; + case OT_CLASS: v->Push(ss->_class_default_delegate); break; + case OT_INSTANCE: v->Push(ss->_instance_default_delegate); break; + case OT_WEAKREF: v->Push(ss->_weakref_default_delegate); break; + default: return sq_throwerror(v,"the type doesn't have a default delegate"); + } + return SQ_OK; +} + +SQRESULT sq_next(HSQUIRRELVM v,SQInteger idx) +{ + SQObjectPtr o=stack_get(v,idx),&refpos = stack_get(v,-1),realkey,val; + if(type(o) == OT_GENERATOR) { + return sq_throwerror(v,"cannot iterate a generator"); + } + int faketojump; + if(!v->FOREACH_OP(o,realkey,val,refpos,0,666,faketojump)) + return SQ_ERROR; + if(faketojump != 666) { + v->Push(realkey); + v->Push(val); + return SQ_OK; + } + return SQ_ERROR; +} + +struct BufState{ + const SQChar *buf; + SQInteger ptr; + SQInteger size; +}; + +WChar buf_lexfeed(SQUserPointer file) +{ + /* Convert an UTF-8 character into a WChar */ + BufState *buf = (BufState *)file; + const char *p = &buf->buf[buf->ptr]; + + if (buf->size < buf->ptr + 1) return 0; + + /* Read the first character, and get the length based on UTF-8 specs. If invalid, bail out. */ + uint len = Utf8EncodedCharLen(*p); + if (len == 0) { + buf->ptr++; + return -1; + } + + /* Read the remaining bits. */ + if (buf->size < buf->ptr + len) return 0; + buf->ptr += len; + + /* Convert the character, and when definitely invalid, bail out as well. */ + WChar c; + if (Utf8Decode(&c, p) != len) return -1; + + return c; +} + +SQRESULT sq_compilebuffer(HSQUIRRELVM v,const SQChar *s,SQInteger size,const SQChar *sourcename,SQBool raiseerror) { + BufState buf; + buf.buf = s; + buf.size = size; + buf.ptr = 0; + return sq_compile(v, buf_lexfeed, &buf, sourcename, raiseerror); +} + +void sq_move(HSQUIRRELVM dest,HSQUIRRELVM src,SQInteger idx) +{ + dest->Push(stack_get(src,idx)); +} + +void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc) +{ + _ss(v)->_printfunc = printfunc; +} + +SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v) +{ + return _ss(v)->_printfunc; +} + +void *sq_malloc(SQUnsignedInteger size) +{ + return SQ_MALLOC(size); +} + +void *sq_realloc(void* p,SQUnsignedInteger oldsize,SQUnsignedInteger newsize) +{ + return SQ_REALLOC(p,oldsize,newsize); +} + +void sq_free(void *p,SQUnsignedInteger size) +{ + SQ_FREE(p,size); +} + diff --git a/src/3rdparty/squirrel/squirrel/sqarray.h b/src/3rdparty/squirrel/squirrel/sqarray.h new file mode 100644 index 0000000..5c26352 --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqarray.h @@ -0,0 +1,87 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQARRAY_H_ +#define _SQARRAY_H_ + +struct SQArray : public CHAINABLE_OBJ +{ +private: + SQArray(SQSharedState *ss,SQInteger nsize){_values.resize(nsize); INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);} + ~SQArray() + { + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); + } +public: + static SQArray* Create(SQSharedState *ss,SQInteger nInitialSize){ + SQArray *newarray=(SQArray*)SQ_MALLOC(sizeof(SQArray)); + new (newarray) SQArray(ss,nInitialSize); + return newarray; + } +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); +#endif + void Finalize(){ + _values.resize(0); + } + bool Get(const SQInteger nidx,SQObjectPtr &val) + { + if(nidx>=0 && nidx<(SQInteger)_values.size()){ + SQObjectPtr &o = _values[nidx]; + val = _realval(o); + return true; + } + else return false; + } + bool Set(const SQInteger nidx,const SQObjectPtr &val) + { + if(nidx>=0 && nidx<(SQInteger)_values.size()){ + _values[nidx]=val; + return true; + } + else return false; + } + SQInteger Next(const SQObjectPtr &refpos,SQObjectPtr &outkey,SQObjectPtr &outval) + { + SQUnsignedInteger idx=TranslateIndex(refpos); + while(idx<_values.size()){ + //first found + outkey=(SQInteger)idx; + SQObjectPtr &o = _values[idx]; + outval = _realval(o); + //return idx for the next iteration + return ++idx; + } + //nothing to iterate anymore + return -1; + } + SQArray *Clone(){SQArray *anew=Create(_opt_ss(this),Size()); anew->_values.copy(_values); return anew; } + SQInteger Size() const {return _values.size();} + void Resize(SQInteger size,SQObjectPtr &fill = _null_) { _values.resize(size,fill); ShrinkIfNeeded(); } + void Reserve(SQInteger size) { _values.reserve(size); } + void Append(const SQObject &o){_values.push_back(o);} + void Extend(const SQArray *a); + SQObjectPtr &Top(){return _values.top();} + void Pop(){_values.pop_back(); ShrinkIfNeeded(); } + bool Insert(SQInteger idx,const SQObject &val){ + if(idx < 0 || idx > (SQInteger)_values.size()) + return false; + _values.insert(idx,val); + return true; + } + void ShrinkIfNeeded() { + if(_values.size() <= _values.capacity()>>2) //shrink the array + _values.shrinktofit(); + } + bool Remove(SQInteger idx){ + if(idx < 0 || idx >= (SQInteger)_values.size()) + return false; + _values.remove(idx); + ShrinkIfNeeded(); + return true; + } + void Release() + { + sq_delete(this,SQArray); + } + SQObjectPtrVec _values; +}; +#endif //_SQARRAY_H_ diff --git a/src/3rdparty/squirrel/squirrel/sqbaselib.cpp b/src/3rdparty/squirrel/squirrel/sqbaselib.cpp new file mode 100644 index 0000000..86a1b11 --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqbaselib.cpp @@ -0,0 +1,962 @@ +/* + * see copyright notice in squirrel.h + */ +/* + * Needs to be first due to a squirrel header defining type() and type() + * being used in some versions of the headers included by algorithm. + */ + +#include "../../../stdafx.h" + +#include +#include "sqpcheader.h" +#include "sqvm.h" +#include "sqstring.h" +#include "sqtable.h" +#include "sqarray.h" +#include "sqfuncproto.h" +#include "sqclosure.h" +#include "sqclass.h" +#include +#include + +#include "../../../safeguards.h" + +bool str2num(const SQChar *s,SQObjectPtr &res) +{ + SQChar *end; + if(strstr(s,".")){ + SQFloat r = SQFloat(strtod(s,&end)); + if(s == end) return false; + res = r; + return true; + } + else{ + SQInteger r = SQInteger(strtol(s,&end,10)); + if(s == end) return false; + res = r; + return true; + } +} + +#ifdef EXPORT_DEFAULT_SQUIRREL_FUNCTIONS +static SQInteger base_dummy(HSQUIRRELVM v) +{ + return 0; +} + +#ifndef NO_GARBAGE_COLLECTOR +static SQInteger base_collectgarbage(HSQUIRRELVM v) +{ + sq_pushinteger(v, sq_collectgarbage(v)); + return 1; +} +#endif + +static SQInteger base_getroottable(HSQUIRRELVM v) +{ + v->Push(v->_roottable); + return 1; +} + +static SQInteger base_getconsttable(HSQUIRRELVM v) +{ + v->Push(_ss(v)->_consts); + return 1; +} + + +static SQInteger base_setroottable(HSQUIRRELVM v) +{ + SQObjectPtr &o=stack_get(v,2); + if(SQ_FAILED(sq_setroottable(v))) return SQ_ERROR; + v->Push(o); + return 1; +} + +static SQInteger base_setconsttable(HSQUIRRELVM v) +{ + SQObjectPtr &o=stack_get(v,2); + if(SQ_FAILED(sq_setconsttable(v))) return SQ_ERROR; + v->Push(o); + return 1; +} + +static SQInteger base_seterrorhandler(HSQUIRRELVM v) +{ + sq_seterrorhandler(v); + return 0; +} + +static SQInteger base_setdebughook(HSQUIRRELVM v) +{ + sq_setdebughook(v); + return 0; +} + +static SQInteger base_enabledebuginfo(HSQUIRRELVM v) +{ + SQObjectPtr &o=stack_get(v,2); + sq_enabledebuginfo(v,(type(o) != OT_NULL)?1:0); + return 0; +} + +static SQInteger base_getstackinfos(HSQUIRRELVM v) +{ + SQInteger level; + SQStackInfos si; + SQInteger seq = 0; + const SQChar *name = NULL; + sq_getinteger(v, -1, &level); + if (SQ_SUCCEEDED(sq_stackinfos(v, level, &si))) + { + const SQChar *fn = "unknown"; + const SQChar *src = "unknown"; + if(si.funcname)fn = si.funcname; + if(si.source)src = si.source; + sq_newtable(v); + sq_pushstring(v, "func", -1); + sq_pushstring(v, fn, -1); + sq_createslot(v, -3); + sq_pushstring(v, "src", -1); + sq_pushstring(v, src, -1); + sq_createslot(v, -3); + sq_pushstring(v, "line", -1); + sq_pushinteger(v, si.line); + sq_createslot(v, -3); + sq_pushstring(v, "locals", -1); + sq_newtable(v); + seq=0; + while ((name = sq_getlocal(v, level, seq))) { + sq_pushstring(v, name, -1); + sq_push(v, -2); + sq_createslot(v, -4); + sq_pop(v, 1); + seq++; + } + sq_createslot(v, -3); + return 1; + } + + return 0; +} +#endif /* EXPORT_DEFAULT_SQUIRREL_FUNCTIONS */ + +static SQInteger base_assert(HSQUIRRELVM v) +{ + if(v->IsFalse(stack_get(v,2))){ + return sq_throwerror(v,"assertion failed"); + } + return 0; +} + +static SQInteger get_slice_params(HSQUIRRELVM v,SQInteger &sidx,SQInteger &eidx,SQObjectPtr &o) +{ + SQInteger top = sq_gettop(v); + sidx=0; + eidx=0; + o=stack_get(v,1); + SQObjectPtr &start=stack_get(v,2); + if(type(start)!=OT_NULL && sq_isnumeric(start)){ + sidx=tointeger(start); + } + if(top>2){ + SQObjectPtr &end=stack_get(v,3); + if(sq_isnumeric(end)){ + eidx=tointeger(end); + } + } + else { + eidx = sq_getsize(v,1); + } + return 1; +} + +static SQInteger base_print(HSQUIRRELVM v) +{ + const SQChar *str; + sq_tostring(v,2); + sq_getstring(v,-1,&str); + if(_ss(v)->_printfunc) _ss(v)->_printfunc(v,"%s",str); + return 0; +} + +#ifdef EXPORT_DEFAULT_SQUIRREL_FUNCTIONS +static SQInteger base_compilestring(HSQUIRRELVM v) +{ + SQInteger nargs=sq_gettop(v); + const SQChar *src=NULL,*name="unnamedbuffer"; + SQInteger size; + sq_getstring(v,2,&src); + size=sq_getsize(v,2); + if(nargs>2){ + sq_getstring(v,3,&name); + } + if(SQ_SUCCEEDED(sq_compilebuffer(v,src,size,name,SQFalse))) + return 1; + else + return SQ_ERROR; +} + +static SQInteger base_newthread(HSQUIRRELVM v) +{ + SQObjectPtr &func = stack_get(v,2); + SQInteger stksize = (_funcproto(_closure(func)->_function)->_stacksize << 1) +2; + HSQUIRRELVM newv = sq_newthread(v, (stksize < MIN_STACK_OVERHEAD + 2)? MIN_STACK_OVERHEAD + 2 : stksize); + sq_move(newv,v,-2); + return 1; +} + +static SQInteger base_suspend(HSQUIRRELVM v) +{ + return sq_suspendvm(v); +} +#endif /* EXPORT_DEFAULT_SQUIRREL_FUNCTIONS */ + +static SQInteger base_array(HSQUIRRELVM v) +{ + SQArray *a; + SQInteger nInitialSize = tointeger(stack_get(v,2)); + SQInteger ret = 1; + if (nInitialSize < 0) { + v->Raise_Error("can't create/resize array with/to size %d", nInitialSize); + nInitialSize = 0; + ret = -1; + } + if(sq_gettop(v) > 2) { + a = SQArray::Create(_ss(v),0); + a->Resize(nInitialSize,stack_get(v,3)); + } + else { + a = SQArray::Create(_ss(v),nInitialSize); + } + v->Push(a); + return ret; +} + +static SQInteger base_type(HSQUIRRELVM v) +{ + SQObjectPtr &o = stack_get(v,2); + v->Push(SQString::Create(_ss(v),GetTypeName(o),-1)); + return 1; +} + +static SQRegFunction base_funcs[]={ + //generic +#ifdef EXPORT_DEFAULT_SQUIRREL_FUNCTIONS + {"seterrorhandler",base_seterrorhandler,2, NULL}, + {"setdebughook",base_setdebughook,2, NULL}, + {"enabledebuginfo",base_enabledebuginfo,2, NULL}, + {"getstackinfos",base_getstackinfos,2, ".n"}, + {"getroottable",base_getroottable,1, NULL}, + {"setroottable",base_setroottable,2, NULL}, + {"getconsttable",base_getconsttable,1, NULL}, + {"setconsttable",base_setconsttable,2, NULL}, +#endif + {"assert",base_assert,2, NULL}, + {"print",base_print,2, NULL}, +#ifdef EXPORT_DEFAULT_SQUIRREL_FUNCTIONS + {"compilestring",base_compilestring,-2, ".ss"}, + {"newthread",base_newthread,2, ".c"}, + {"suspend",base_suspend,-1, NULL}, +#endif + {"array",base_array,-2, ".n"}, + {"type",base_type,2, NULL}, +#ifdef EXPORT_DEFAULT_SQUIRREL_FUNCTIONS + {"dummy",base_dummy,0,NULL}, +#ifndef NO_GARBAGE_COLLECTOR + {"collectgarbage",base_collectgarbage,1, "t"}, +#endif +#endif + {0,0,0,0} +}; + +void sq_base_register(HSQUIRRELVM v) +{ + SQInteger i=0; + sq_pushroottable(v); + while(base_funcs[i].name!=0) { + sq_pushstring(v,base_funcs[i].name,-1); + sq_newclosure(v,base_funcs[i].f,0); + sq_setnativeclosurename(v,-1,base_funcs[i].name); + sq_setparamscheck(v,base_funcs[i].nparamscheck,base_funcs[i].typemask); + sq_createslot(v,-3); + i++; + } + sq_pushstring(v,"_version_",-1); + sq_pushstring(v,SQUIRREL_VERSION,-1); + sq_createslot(v,-3); + sq_pushstring(v,"_charsize_",-1); + sq_pushinteger(v,sizeof(SQChar)); + sq_createslot(v,-3); + sq_pushstring(v,"_intsize_",-1); + sq_pushinteger(v,sizeof(SQInteger)); + sq_createslot(v,-3); + sq_pushstring(v,"_floatsize_",-1); + sq_pushinteger(v,sizeof(SQFloat)); + sq_createslot(v,-3); + sq_pop(v,1); +} + +static SQInteger default_delegate_len(HSQUIRRELVM v) +{ + v->Push(SQInteger(sq_getsize(v,1))); + return 1; +} + +static SQInteger default_delegate_tofloat(HSQUIRRELVM v) +{ + SQObjectPtr &o=stack_get(v,1); + switch(type(o)){ + case OT_STRING:{ + SQObjectPtr res; + if(str2num(_stringval(o),res)){ + v->Push(SQObjectPtr(tofloat(res))); + break; + }} + return sq_throwerror(v, "cannot convert the string"); + break; + case OT_INTEGER:case OT_FLOAT: + v->Push(SQObjectPtr(tofloat(o))); + break; + case OT_BOOL: + v->Push(SQObjectPtr((SQFloat)(_integer(o)?1:0))); + break; + default: + v->Push(_null_); + break; + } + return 1; +} + +static SQInteger default_delegate_tointeger(HSQUIRRELVM v) +{ + SQObjectPtr &o=stack_get(v,1); + switch(type(o)){ + case OT_STRING:{ + SQObjectPtr res; + if(str2num(_stringval(o),res)){ + v->Push(SQObjectPtr(tointeger(res))); + break; + }} + return sq_throwerror(v, "cannot convert the string"); + break; + case OT_INTEGER:case OT_FLOAT: + v->Push(SQObjectPtr(tointeger(o))); + break; + case OT_BOOL: + v->Push(SQObjectPtr(_integer(o)?(SQInteger)1:(SQInteger)0)); + break; + default: + v->Push(_null_); + break; + } + return 1; +} + +static SQInteger default_delegate_tostring(HSQUIRRELVM v) +{ + sq_tostring(v,1); + return 1; +} + +static SQInteger obj_delegate_weakref(HSQUIRRELVM v) +{ + sq_weakref(v,1); + return 1; +} + +static SQInteger obj_clear(HSQUIRRELVM v) +{ + return sq_clear(v,-1); +} + + +static SQInteger number_delegate_tochar(HSQUIRRELVM v) +{ + SQObject &o=stack_get(v,1); + SQChar c = (SQChar)tointeger(o); + v->Push(SQString::Create(_ss(v),(const SQChar *)&c,1)); + return 1; +} + + +///////////////////////////////////////////////////////////////// +//TABLE DEFAULT DELEGATE + +static SQInteger table_rawdelete(HSQUIRRELVM v) +{ + if(SQ_FAILED(sq_rawdeleteslot(v,1,SQTrue))) + return SQ_ERROR; + return 1; +} + + +static SQInteger container_rawexists(HSQUIRRELVM v) +{ + if(SQ_SUCCEEDED(sq_rawget(v,-2))) { + sq_pushbool(v,SQTrue); + return 1; + } + sq_pushbool(v,SQFalse); + return 1; +} + +static SQInteger table_rawset(HSQUIRRELVM v) +{ + return sq_rawset(v,-3); +} + + +static SQInteger table_rawget(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_rawget(v,-2))?1:SQ_ERROR; +} + + +SQRegFunction SQSharedState::_table_default_delegate_funcz[]={ + {"len",default_delegate_len,1, "t"}, + {"rawget",table_rawget,2, "t"}, + {"rawset",table_rawset,3, "t"}, + {"rawdelete",table_rawdelete,2, "t"}, + {"rawin",container_rawexists,2, "t"}, + {"weakref",obj_delegate_weakref,1, NULL }, + {"tostring",default_delegate_tostring,1, "."}, + {"clear",obj_clear,1, "."}, + {0,0,0,0} +}; + +//ARRAY DEFAULT DELEGATE/////////////////////////////////////// + +static SQInteger array_append(HSQUIRRELVM v) +{ + return sq_arrayappend(v,-2); +} + +static SQInteger array_extend(HSQUIRRELVM v) +{ + _array(stack_get(v,1))->Extend(_array(stack_get(v,2))); + return 0; +} + +static SQInteger array_reverse(HSQUIRRELVM v) +{ + return sq_arrayreverse(v,-1); +} + +static SQInteger array_pop(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_arraypop(v,1,SQTrue))?1:SQ_ERROR; +} + +static SQInteger array_top(HSQUIRRELVM v) +{ + SQObject &o=stack_get(v,1); + if(_array(o)->Size()>0){ + v->Push(_array(o)->Top()); + return 1; + } + else return sq_throwerror(v,"top() on a empty array"); +} + +static SQInteger array_insert(HSQUIRRELVM v) +{ + SQObject &o=stack_get(v,1); + SQObject &idx=stack_get(v,2); + SQObject &val=stack_get(v,3); + if(!_array(o)->Insert(tointeger(idx),val)) + return sq_throwerror(v,"index out of range"); + return 0; +} + +static SQInteger array_remove(HSQUIRRELVM v) +{ + SQObject &o = stack_get(v, 1); + SQObject &idx = stack_get(v, 2); + if(!sq_isnumeric(idx)) return sq_throwerror(v, "wrong type"); + SQObjectPtr val; + if(_array(o)->Get(tointeger(idx), val)) { + _array(o)->Remove(tointeger(idx)); + v->Push(val); + return 1; + } + return sq_throwerror(v, "idx out of range"); +} + +static SQInteger array_resize(HSQUIRRELVM v) +{ + SQObject &o = stack_get(v, 1); + SQObject &nsize = stack_get(v, 2); + SQObjectPtr fill; + if(sq_isnumeric(nsize)) { + if(sq_gettop(v) > 2) + fill = stack_get(v, 3); + _array(o)->Resize(tointeger(nsize),fill); + return 0; + } + return sq_throwerror(v, "size must be a number"); +} + + +bool _sort_compare(HSQUIRRELVM v,SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQInteger &ret) +{ + if(func < 0) { + if(!v->ObjCmp(a,b,ret)) return false; + } + else { + SQInteger top = sq_gettop(v); + sq_push(v, func); + sq_pushroottable(v); + v->Push(a); + v->Push(b); + if(SQ_FAILED(sq_call(v, 3, SQTrue, SQFalse))) { + if(!sq_isstring( v->_lasterror)) + v->Raise_Error("compare func failed"); + return false; + } + if(SQ_FAILED(sq_getinteger(v, -1, &ret))) { + v->Raise_Error("numeric value expected as return value of the compare function"); + return false; + } + sq_settop(v, top); + return true; + } + return true; +} + +bool _hsort_sift_down(HSQUIRRELVM v,SQArray *arr, SQInteger root, SQInteger bottom, SQInteger func) +{ + SQInteger maxChild; + SQInteger done = 0; + SQInteger ret; + SQInteger root2; + while (((root2 = root * 2) <= bottom) && (!done)) + { + if (root2 == bottom) { + maxChild = root2; + } + else { + if(!_sort_compare(v,arr->_values[root2],arr->_values[root2 + 1],func,ret)) + return false; + if (ret > 0) { + maxChild = root2; + } + else { + maxChild = root2 + 1; + } + + } + + if(!_sort_compare(v,arr->_values[root],arr->_values[maxChild],func,ret)) + return false; + if (ret < 0) { + if (root == maxChild) { + v->Raise_Error("inconsistent compare function"); + return false; // We'd be swapping ourselve. The compare function is incorrect + } + _Swap(arr->_values[root],arr->_values[maxChild]); + root = maxChild; + } + else { + done = 1; + } + } + return true; +} + +bool _hsort(HSQUIRRELVM v,SQObjectPtr &arr, SQInteger l, SQInteger r,SQInteger func) +{ + SQArray *a = _array(arr); + SQInteger i; + SQInteger array_size = a->Size(); + for (i = (array_size / 2); i >= 0; i--) { + if(!_hsort_sift_down(v,a, i, array_size - 1,func)) return false; + } + + for (i = array_size-1; i >= 1; i--) + { + _Swap(a->_values[0],a->_values[i]); + if(!_hsort_sift_down(v,a, 0, i-1,func)) return false; + } + return true; +} + +static SQInteger array_sort(HSQUIRRELVM v) +{ + SQInteger func = -1; + SQObjectPtr &o = stack_get(v,1); + if(_array(o)->Size() > 1) { + if(sq_gettop(v) == 2) func = 2; + if(!_hsort(v, o, 0, _array(o)->Size()-1, func)) + return SQ_ERROR; + + } + return 0; +} + +static SQInteger array_slice(HSQUIRRELVM v) +{ + SQInteger sidx,eidx; + SQObjectPtr o; + if(get_slice_params(v,sidx,eidx,o)==-1)return -1; + SQInteger alen = _array(o)->Size(); + if(sidx < 0)sidx = alen + sidx; + if(eidx < 0)eidx = alen + eidx; + if(eidx < sidx)return sq_throwerror(v,"wrong indexes"); + if(eidx > alen)return sq_throwerror(v,"slice out of range"); + SQArray *arr=SQArray::Create(_ss(v),eidx-sidx); + SQObjectPtr t; + SQInteger count=0; + for(SQInteger i=sidx;iGet(i,t); + arr->Set(count++,t); + } + v->Push(arr); + return 1; + +} + +SQRegFunction SQSharedState::_array_default_delegate_funcz[]={ + {"len",default_delegate_len,1, "a"}, + {"append",array_append,2, "a"}, + {"extend",array_extend,2, "aa"}, + {"push",array_append,2, "a"}, + {"pop",array_pop,1, "a"}, + {"top",array_top,1, "a"}, + {"insert",array_insert,3, "an"}, + {"remove",array_remove,2, "an"}, + {"resize",array_resize,-2, "an"}, + {"reverse",array_reverse,1, "a"}, + {"sort",array_sort,-1, "ac"}, + {"slice",array_slice,-1, "ann"}, + {"weakref",obj_delegate_weakref,1, NULL }, + {"tostring",default_delegate_tostring,1, "."}, + {"clear",obj_clear,1, "."}, + {0,0,0,0} +}; + +//STRING DEFAULT DELEGATE////////////////////////// +static SQInteger string_slice(HSQUIRRELVM v) +{ + SQInteger sidx,eidx; + SQObjectPtr o; + if(SQ_FAILED(get_slice_params(v,sidx,eidx,o)))return -1; + SQInteger slen = _string(o)->_len; + if(sidx < 0)sidx = slen + sidx; + if(eidx < 0)eidx = slen + eidx; + if(eidx < sidx) return sq_throwerror(v,"wrong indexes"); + if(eidx > slen) return sq_throwerror(v,"slice out of range"); + v->Push(SQString::Create(_ss(v),&_stringval(o)[sidx],eidx-sidx)); + return 1; +} + +static SQInteger string_find(HSQUIRRELVM v) +{ + SQInteger top,start_idx=0; + const SQChar *str,*substr,*ret; + if(((top=sq_gettop(v))>1) && SQ_SUCCEEDED(sq_getstring(v,1,&str)) && SQ_SUCCEEDED(sq_getstring(v,2,&substr))){ + if(top>2)sq_getinteger(v,3,&start_idx); + if((sq_getsize(v,1)>start_idx) && (start_idx>=0)){ + ret=strstr(&str[start_idx],substr); + if(ret){ + sq_pushinteger(v,(SQInteger)(ret-str)); + return 1; + } + } + return 0; + } + return sq_throwerror(v,"invalid param"); +} + +#define STRING_TOFUNCZ(func) static SQInteger string_##func(HSQUIRRELVM v) \ +{ \ + SQObject str=stack_get(v,1); \ + SQInteger len=_string(str)->_len; \ + const SQChar *sThis=_stringval(str); \ + SQChar *sNew=(_ss(v)->GetScratchPad(len)); \ + for(SQInteger i=0;iPush(SQString::Create(_ss(v),sNew,len)); \ + return 1; \ +} + + +STRING_TOFUNCZ(tolower) +STRING_TOFUNCZ(toupper) + +SQRegFunction SQSharedState::_string_default_delegate_funcz[]={ + {"len",default_delegate_len,1, "s"}, + {"tointeger",default_delegate_tointeger,1, "s"}, + {"tofloat",default_delegate_tofloat,1, "s"}, + {"tostring",default_delegate_tostring,1, "."}, + {"slice",string_slice,-1, " s n n"}, + {"find",string_find,-2, "s s n "}, + {"tolower",string_tolower,1, "s"}, + {"toupper",string_toupper,1, "s"}, + {"weakref",obj_delegate_weakref,1, NULL }, + {0,0,0,0} +}; + +//INTEGER DEFAULT DELEGATE////////////////////////// +SQRegFunction SQSharedState::_number_default_delegate_funcz[]={ + {"tointeger",default_delegate_tointeger,1, "n|b"}, + {"tofloat",default_delegate_tofloat,1, "n|b"}, + {"tostring",default_delegate_tostring,1, "."}, + {"tochar",number_delegate_tochar,1, "n|b"}, + {"weakref",obj_delegate_weakref,1, NULL }, + {0,0,0,0} +}; + +//CLOSURE DEFAULT DELEGATE////////////////////////// +static SQInteger closure_pcall(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue,SQFalse))?1:SQ_ERROR; +} + +static SQInteger closure_call(HSQUIRRELVM v) +{ + return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue,SQTrue))?1:SQ_ERROR; +} + +static SQInteger _closure_acall(HSQUIRRELVM v,SQBool raiseerror) +{ + SQArray *aparams=_array(stack_get(v,2)); + SQInteger nparams=aparams->Size(); + v->Push(stack_get(v,1)); + for(SQInteger i=0;iPush(aparams->_values[i]); + return SQ_SUCCEEDED(sq_call(v,nparams,SQTrue,raiseerror))?1:SQ_ERROR; +} + +static SQInteger closure_acall(HSQUIRRELVM v) +{ + return _closure_acall(v,SQTrue); +} + +static SQInteger closure_pacall(HSQUIRRELVM v) +{ + return _closure_acall(v,SQFalse); +} + +static SQInteger closure_bindenv(HSQUIRRELVM v) +{ + if(SQ_FAILED(sq_bindenv(v,1))) + return SQ_ERROR; + return 1; +} + +static SQInteger closure_getinfos(HSQUIRRELVM v) { + SQObject o = stack_get(v,1); + SQTable *res = SQTable::Create(_ss(v),4); + if(type(o) == OT_CLOSURE) { + SQFunctionProto *f = _funcproto(_closure(o)->_function); + SQInteger nparams = f->_nparameters + (f->_varparams?1:0); + SQObjectPtr params = SQArray::Create(_ss(v),nparams); + for(SQInteger n = 0; n_nparameters; n++) { + _array(params)->Set((SQInteger)n,f->_parameters[n]); + } + if(f->_varparams) { + _array(params)->Set(nparams-1,SQString::Create(_ss(v),"...",-1)); + } + res->NewSlot(SQString::Create(_ss(v),"native",-1),false); + res->NewSlot(SQString::Create(_ss(v),"name",-1),f->_name); + res->NewSlot(SQString::Create(_ss(v),"src",-1),f->_sourcename); + res->NewSlot(SQString::Create(_ss(v),"parameters",-1),params); + res->NewSlot(SQString::Create(_ss(v),"varargs",-1),f->_varparams); + } + else { //OT_NATIVECLOSURE + SQNativeClosure *nc = _nativeclosure(o); + res->NewSlot(SQString::Create(_ss(v),"native",-1),true); + res->NewSlot(SQString::Create(_ss(v),"name",-1),nc->_name); + res->NewSlot(SQString::Create(_ss(v),"paramscheck",-1),nc->_nparamscheck); + SQObjectPtr typecheck; + if(nc->_typecheck.size() > 0) { + typecheck = + SQArray::Create(_ss(v), nc->_typecheck.size()); + for(SQUnsignedInteger n = 0; n_typecheck.size(); n++) { + _array(typecheck)->Set((SQInteger)n,nc->_typecheck[n]); + } + } + res->NewSlot(SQString::Create(_ss(v),"typecheck",-1),typecheck); + } + v->Push(res); + return 1; +} + + +SQRegFunction SQSharedState::_closure_default_delegate_funcz[]={ + {"call",closure_call,-1, "c"}, + {"pcall",closure_pcall,-1, "c"}, + {"acall",closure_acall,2, "ca"}, + {"pacall",closure_pacall,2, "ca"}, + {"weakref",obj_delegate_weakref,1, NULL }, + {"tostring",default_delegate_tostring,1, "."}, + {"bindenv",closure_bindenv,2, "c x|y|t"}, + {"getinfos",closure_getinfos,1, "c"}, + {0,0,0,0} +}; + +//GENERATOR DEFAULT DELEGATE +static SQInteger generator_getstatus(HSQUIRRELVM v) +{ + SQObject &o=stack_get(v,1); + switch(_generator(o)->_state){ + case SQGenerator::eSuspended:v->Push(SQString::Create(_ss(v),"suspended"));break; + case SQGenerator::eRunning:v->Push(SQString::Create(_ss(v),"running"));break; + case SQGenerator::eDead:v->Push(SQString::Create(_ss(v),"dead"));break; + } + return 1; +} + +SQRegFunction SQSharedState::_generator_default_delegate_funcz[]={ + {"getstatus",generator_getstatus,1, "g"}, + {"weakref",obj_delegate_weakref,1, NULL }, + {"tostring",default_delegate_tostring,1, "."}, + {0,0,0,0} +}; + +//THREAD DEFAULT DELEGATE + +static SQInteger thread_call(HSQUIRRELVM v) +{ + + SQObjectPtr o = stack_get(v,1); + if(type(o) == OT_THREAD) { + SQInteger nparams = sq_gettop(v); + _thread(o)->Push(_thread(o)->_roottable); + for(SQInteger i = 2; i<(nparams+1); i++) + sq_move(_thread(o),v,i); + if(SQ_SUCCEEDED(sq_call(_thread(o),nparams,SQTrue,SQFalse))) { + sq_move(v,_thread(o),-1); + sq_pop(_thread(o),1); + return 1; + } + v->_lasterror = _thread(o)->_lasterror; + return SQ_ERROR; + } + return sq_throwerror(v,"wrong parameter"); +} + +static SQInteger thread_wakeup(HSQUIRRELVM v) +{ + SQObjectPtr o = stack_get(v,1); + if(type(o) == OT_THREAD) { + SQVM *thread = _thread(o); + SQInteger state = sq_getvmstate(thread); + if(state != SQ_VMSTATE_SUSPENDED) { + switch(state) { + case SQ_VMSTATE_IDLE: + return sq_throwerror(v,"cannot wakeup a idle thread"); + break; + case SQ_VMSTATE_RUNNING: + return sq_throwerror(v,"cannot wakeup a running thread"); + break; + } + } + + SQInteger wakeupret = sq_gettop(v)>1?1:0; + if(wakeupret) { + sq_move(thread,v,2); + } + if(SQ_SUCCEEDED(sq_wakeupvm(thread,wakeupret,SQTrue,SQTrue,SQFalse))) { + sq_move(v,thread,-1); + sq_pop(thread,1); //pop retval + if(sq_getvmstate(thread) == SQ_VMSTATE_IDLE) { + sq_settop(thread,1); //pop roottable + } + return 1; + } + sq_settop(thread,1); + v->_lasterror = thread->_lasterror; + return SQ_ERROR; + } + return sq_throwerror(v,"wrong parameter"); +} + +static SQInteger thread_getstatus(HSQUIRRELVM v) +{ + SQObjectPtr &o = stack_get(v,1); + switch(sq_getvmstate(_thread(o))) { + case SQ_VMSTATE_IDLE: + sq_pushstring(v,"idle",-1); + break; + case SQ_VMSTATE_RUNNING: + sq_pushstring(v,"running",-1); + break; + case SQ_VMSTATE_SUSPENDED: + sq_pushstring(v,"suspended",-1); + break; + default: + return sq_throwerror(v,"internal VM error"); + } + return 1; +} + +SQRegFunction SQSharedState::_thread_default_delegate_funcz[] = { + {"call", thread_call, -1, "v"}, + {"wakeup", thread_wakeup, -1, "v"}, + {"getstatus", thread_getstatus, 1, "v"}, + {"weakref",obj_delegate_weakref,1, NULL }, + {"tostring",default_delegate_tostring,1, "."}, + {0,0,0,0}, +}; + +static SQInteger class_getattributes(HSQUIRRELVM v) +{ + if(SQ_SUCCEEDED(sq_getattributes(v,-2))) + return 1; + return SQ_ERROR; +} + +static SQInteger class_setattributes(HSQUIRRELVM v) +{ + if(SQ_SUCCEEDED(sq_setattributes(v,-3))) + return 1; + return SQ_ERROR; +} + +static SQInteger class_instance(HSQUIRRELVM v) +{ + if(SQ_SUCCEEDED(sq_createinstance(v,-1))) + return 1; + return SQ_ERROR; +} + +SQRegFunction SQSharedState::_class_default_delegate_funcz[] = { + {"getattributes", class_getattributes, 2, "y."}, + {"setattributes", class_setattributes, 3, "y.."}, + {"rawin",container_rawexists,2, "y"}, + {"weakref",obj_delegate_weakref,1, NULL }, + {"tostring",default_delegate_tostring,1, "."}, + {"instance",class_instance,1, "y"}, + {0,0,0,0} +}; + +static SQInteger instance_getclass(HSQUIRRELVM v) +{ + if(SQ_SUCCEEDED(sq_getclass(v,1))) + return 1; + return SQ_ERROR; +} + +SQRegFunction SQSharedState::_instance_default_delegate_funcz[] = { + {"getclass", instance_getclass, 1, "x"}, + {"rawin",container_rawexists,2, "x"}, + {"weakref",obj_delegate_weakref,1, NULL }, + {"tostring",default_delegate_tostring,1, "."}, + {0,0,0,0} +}; + +static SQInteger weakref_ref(HSQUIRRELVM v) +{ + if(SQ_FAILED(sq_getweakrefval(v,1))) + return SQ_ERROR; + return 1; +} + +SQRegFunction SQSharedState::_weakref_default_delegate_funcz[] = { + {"ref",weakref_ref,1, "r"}, + {"weakref",obj_delegate_weakref,1, NULL }, + {"tostring",default_delegate_tostring,1, "."}, + {0,0,0,0} +}; + + diff --git a/src/3rdparty/squirrel/squirrel/sqclass.cpp b/src/3rdparty/squirrel/squirrel/sqclass.cpp new file mode 100644 index 0000000..aa1bca0 --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqclass.cpp @@ -0,0 +1,199 @@ +/* + * see copyright notice in squirrel.h + */ + +#include "../../../stdafx.h" + +#include "sqpcheader.h" +#include "sqvm.h" +#include "sqtable.h" +#include "sqclass.h" +#include "sqclosure.h" + +#include "../../../safeguards.h" + +SQClass::SQClass(SQSharedState *ss,SQClass *base) +{ + _base = base; + _typetag = 0; + _hook = NULL; + _udsize = 0; + _metamethods.resize(MT_LAST); //size it to max size + if(_base) { + _defaultvalues.copy(base->_defaultvalues); + _methods.copy(base->_methods); + _metamethods.copy(base->_metamethods); + __ObjAddRef(_base); + } + _members = base?base->_members->Clone() : SQTable::Create(ss,0); + __ObjAddRef(_members); + _locked = false; + INIT_CHAIN(); + ADD_TO_CHAIN(&_sharedstate->_gc_chain, this); +} + +void SQClass::Finalize() { + _attributes = _null_; + _defaultvalues.resize(0); + _methods.resize(0); + _metamethods.resize(0); + __ObjRelease(_members); + if(_base) { + __ObjRelease(_base); + } +} + +SQClass::~SQClass() +{ + REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); + Finalize(); +} + +bool SQClass::NewSlot(SQSharedState *ss,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic) +{ + SQObjectPtr temp; + if(_locked) + return false; //the class already has an instance so cannot be modified + if(_members->Get(key,temp) && _isfield(temp)) //overrides the default value + { + _defaultvalues[_member_idx(temp)].val = val; + return true; + } + if(type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE || bstatic) { + SQInteger mmidx; + if((type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE) && + (mmidx = ss->GetMetaMethodIdxByName(key)) != -1) { + _metamethods[mmidx] = val; + } + else { + if(type(temp) == OT_NULL) { + SQClassMember m; + m.val = val; + _members->NewSlot(key,SQObjectPtr(_make_method_idx(_methods.size()))); + _methods.push_back(m); + } + else { + _methods[_member_idx(temp)].val = val; + } + } + return true; + } + SQClassMember m; + m.val = val; + _members->NewSlot(key,SQObjectPtr(_make_field_idx(_defaultvalues.size()))); + _defaultvalues.push_back(m); + return true; +} + +SQInstance *SQClass::CreateInstance() +{ + if(!_locked) Lock(); + return SQInstance::Create(_opt_ss(this),this); +} + +SQInteger SQClass::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval) +{ + SQObjectPtr oval; + SQInteger idx = _members->Next(false,refpos,outkey,oval); + if(idx != -1) { + if(_ismethod(oval)) { + outval = _methods[_member_idx(oval)].val; + } + else { + SQObjectPtr &o = _defaultvalues[_member_idx(oval)].val; + outval = _realval(o); + } + } + return idx; +} + +bool SQClass::SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val) +{ + SQObjectPtr idx; + if(_members->Get(key,idx)) { + if(_isfield(idx)) + _defaultvalues[_member_idx(idx)].attrs = val; + else + _methods[_member_idx(idx)].attrs = val; + return true; + } + return false; +} + +bool SQClass::GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval) +{ + SQObjectPtr idx; + if(_members->Get(key,idx)) { + outval = (_isfield(idx)?_defaultvalues[_member_idx(idx)].attrs:_methods[_member_idx(idx)].attrs); + return true; + } + return false; +} + +/////////////////////////////////////////////////////////////////////// +void SQInstance::Init(SQSharedState *ss) +{ + _userpointer = NULL; + _hook = NULL; + __ObjAddRef(_class); + _delegate = _class->_members; + INIT_CHAIN(); + ADD_TO_CHAIN(&_sharedstate->_gc_chain, this); +} + +SQInstance::SQInstance(SQSharedState *ss, SQClass *c, SQInteger memsize) +{ + _memsize = memsize; + _class = c; + SQUnsignedInteger nvalues = _class->_defaultvalues.size(); + for(SQUnsignedInteger n = 0; n < nvalues; n++) { + new (&_values[n]) SQObjectPtr(_class->_defaultvalues[n].val); + } + Init(ss); +} + +SQInstance::SQInstance(SQSharedState *ss, SQInstance *i, SQInteger memsize) +{ + _memsize = memsize; + _class = i->_class; + SQUnsignedInteger nvalues = _class->_defaultvalues.size(); + for(SQUnsignedInteger n = 0; n < nvalues; n++) { + new (&_values[n]) SQObjectPtr(i->_values[n]); + } + Init(ss); +} + +void SQInstance::Finalize() +{ + SQUnsignedInteger nvalues = _class->_defaultvalues.size(); + __ObjRelease(_class); + for(SQUnsignedInteger i = 0; i < nvalues; i++) { + _values[i] = _null_; + } +} + +SQInstance::~SQInstance() +{ + REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); + if(_class){ Finalize(); } //if _class is null it was already finalized by the GC +} + +bool SQInstance::GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res) +{ + if(type(_class->_metamethods[mm]) != OT_NULL) { + res = _class->_metamethods[mm]; + return true; + } + return false; +} + +bool SQInstance::InstanceOf(SQClass *trg) +{ + SQClass *parent = _class; + while(parent != NULL) { + if(parent == trg) + return true; + parent = parent->_base; + } + return false; +} diff --git a/src/3rdparty/squirrel/squirrel/sqclass.h b/src/3rdparty/squirrel/squirrel/sqclass.h new file mode 100644 index 0000000..895c053 --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqclass.h @@ -0,0 +1,162 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQCLASS_H_ +#define _SQCLASS_H_ + +struct SQInstance; + +struct SQClassMember { + SQClassMember(){} + SQClassMember(const SQClassMember &o) { + val = o.val; + attrs = o.attrs; + } + SQObjectPtr val; + SQObjectPtr attrs; +}; + +typedef sqvector SQClassMemberVec; + +#define MEMBER_TYPE_METHOD 0x01000000 +#define MEMBER_TYPE_FIELD 0x02000000 + +#define _ismethod(o) (_integer(o)&MEMBER_TYPE_METHOD) +#define _isfield(o) (_integer(o)&MEMBER_TYPE_FIELD) +#define _make_method_idx(i) ((SQInteger)(MEMBER_TYPE_METHOD|i)) +#define _make_field_idx(i) ((SQInteger)(MEMBER_TYPE_FIELD|i)) +#define _member_type(o) (_integer(o)&0xFF000000) +#define _member_idx(o) (_integer(o)&0x00FFFFFF) + +struct SQClass : public CHAINABLE_OBJ +{ + SQClass(SQSharedState *ss,SQClass *base); +public: + static SQClass* Create(SQSharedState *ss,SQClass *base) { + SQClass *newclass = (SQClass *)SQ_MALLOC(sizeof(SQClass)); + new (newclass) SQClass(ss, base); + return newclass; + } + ~SQClass(); + bool NewSlot(SQSharedState *ss, const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic); + bool Get(const SQObjectPtr &key,SQObjectPtr &val) { + if(_members->Get(key,val)) { + if(_isfield(val)) { + SQObjectPtr &o = _defaultvalues[_member_idx(val)].val; + val = _realval(o); + } + else { + val = _methods[_member_idx(val)].val; + } + return true; + } + return false; + } + bool SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val); + bool GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval); + void Lock() { _locked = true; if(_base) _base->Lock(); } + void Release() { + if (_hook) { _hook(_typetag,0);} + sq_delete(this, SQClass); + } + void Finalize(); +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable ** ); +#endif + SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); + SQInstance *CreateInstance(); + SQTable *_members; + SQClass *_base; + SQClassMemberVec _defaultvalues; + SQClassMemberVec _methods; + SQObjectPtrVec _metamethods; + SQObjectPtr _attributes; + SQUserPointer _typetag; + SQRELEASEHOOK _hook; + bool _locked; + SQInteger _udsize; +}; + +#define calcinstancesize(_theclass_) \ + (_theclass_->_udsize + sizeof(SQInstance) + (sizeof(SQObjectPtr)*(_theclass_->_defaultvalues.size()>0?_theclass_->_defaultvalues.size()-1:0))) + +struct SQInstance : public SQDelegable +{ + void Init(SQSharedState *ss); + SQInstance(SQSharedState *ss, SQClass *c, SQInteger memsize); + SQInstance(SQSharedState *ss, SQInstance *c, SQInteger memsize); +public: + static SQInstance* Create(SQSharedState *ss,SQClass *theclass) { + + SQInteger size = calcinstancesize(theclass); + SQInstance *newinst = (SQInstance *)SQ_MALLOC(size); + new (newinst) SQInstance(ss, theclass,size); + if(theclass->_udsize) { + newinst->_userpointer = ((unsigned char *)newinst) + (size - theclass->_udsize); + } + return newinst; + } + SQInstance *Clone(SQSharedState *ss) + { + SQInteger size = calcinstancesize(_class); + SQInstance *newinst = (SQInstance *)SQ_MALLOC(size); + new (newinst) SQInstance(ss, this,size); + if(_class->_udsize) { + newinst->_userpointer = ((unsigned char *)newinst) + (size - _class->_udsize); + } + return newinst; + } + ~SQInstance(); + bool Get(const SQObjectPtr &key,SQObjectPtr &val) { + if(_class->_members->Get(key,val)) { + if(_isfield(val)) { + SQObjectPtr &o = _values[_member_idx(val)]; + val = _realval(o); + } + else { + val = _class->_methods[_member_idx(val)].val; + } + return true; + } + return false; + } + bool Set(const SQObjectPtr &key,const SQObjectPtr &val) { + SQObjectPtr idx; + if(_class->_members->Get(key,idx) && _isfield(idx)) { + _values[_member_idx(idx)] = val; + return true; + } + return false; + } + void Release() { + _uiRef++; + try { + if (_hook) { _hook(_userpointer,0);} + } catch (...) { + _uiRef--; + if (_uiRef == 0) { + SQInteger size = _memsize; + this->~SQInstance(); + SQ_FREE(this, size); + } + throw; + } + _uiRef--; + if(_uiRef > 0) return; + SQInteger size = _memsize; + this->~SQInstance(); + SQ_FREE(this, size); + } + void Finalize(); +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable ** ); +#endif + bool InstanceOf(SQClass *trg); + bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res); + + SQClass *_class; + SQUserPointer _userpointer; + SQRELEASEHOOK _hook; + SQInteger _memsize; + SQObjectPtr _values[1]; +}; + +#endif //_SQCLASS_H_ diff --git a/src/3rdparty/squirrel/squirrel/sqclosure.h b/src/3rdparty/squirrel/squirrel/sqclosure.h new file mode 100644 index 0000000..a42dcd5 --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqclosure.h @@ -0,0 +1,122 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQCLOSURE_H_ +#define _SQCLOSURE_H_ + +struct SQFunctionProto; + +struct SQClosure : public CHAINABLE_OBJ +{ +private: + SQClosure(SQSharedState *ss,SQFunctionProto *func){_function=func; INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);} +public: + static SQClosure *Create(SQSharedState *ss,SQFunctionProto *func){ + SQClosure *nc=(SQClosure*)SQ_MALLOC(sizeof(SQClosure)); + new (nc) SQClosure(ss,func); + return nc; + } + void Release(){ + sq_delete(this,SQClosure); + } + SQClosure *Clone() + { + SQClosure * ret = SQClosure::Create(_opt_ss(this),_funcproto(_function)); + ret->_env = _env; + ret->_outervalues.copy(_outervalues); + ret->_defaultparams.copy(_defaultparams); + return ret; + } + ~SQClosure() + { + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); + } + bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write); + static bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret); +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + void Finalize(){_outervalues.resize(0); } +#endif + SQObjectPtr _env; + SQObjectPtr _function; + SQObjectPtrVec _outervalues; + SQObjectPtrVec _defaultparams; +}; +////////////////////////////////////////////// +struct SQGenerator : public CHAINABLE_OBJ +{ + enum SQGeneratorState{eRunning,eSuspended,eDead}; +private: + SQGenerator(SQSharedState *ss,SQClosure *closure){_closure=closure;_state=eRunning;_ci._generator=NULL;INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);} +public: + static SQGenerator *Create(SQSharedState *ss,SQClosure *closure){ + SQGenerator *nc=(SQGenerator*)SQ_MALLOC(sizeof(SQGenerator)); + new (nc) SQGenerator(ss,closure); + return nc; + } + ~SQGenerator() + { + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); + } + void Kill(){ + _state=eDead; + _stack.resize(0); + _closure=_null_;} + void Release(){ + sq_delete(this,SQGenerator); + } + bool Yield(SQVM *v); + bool Resume(SQVM *v,SQInteger target); +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + void Finalize(){_stack.resize(0);_closure=_null_;} +#endif + SQObjectPtr _closure; + SQObjectPtrVec _stack; + SQObjectPtrVec _vargsstack; + SQVM::CallInfo _ci; + ExceptionsTraps _etraps; + SQGeneratorState _state; +}; + +struct SQNativeClosure : public CHAINABLE_OBJ +{ +private: + SQNativeClosure(SQSharedState *ss,SQFUNCTION func) : _nparamscheck(0) {_function=func;INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); } +public: + static SQNativeClosure *Create(SQSharedState *ss,SQFUNCTION func) + { + SQNativeClosure *nc=(SQNativeClosure*)SQ_MALLOC(sizeof(SQNativeClosure)); + new (nc) SQNativeClosure(ss,func); + return nc; + } + SQNativeClosure *Clone() + { + SQNativeClosure * ret = SQNativeClosure::Create(_opt_ss(this),_function); + ret->_env = _env; + ret->_name = _name; + ret->_outervalues.copy(_outervalues); + ret->_typecheck.copy(_typecheck); + ret->_nparamscheck = _nparamscheck; + return ret; + } + ~SQNativeClosure() + { + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); + } + void Release(){ + sq_delete(this,SQNativeClosure); + } +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + void Finalize(){_outervalues.resize(0);} +#endif + SQInteger _nparamscheck; + SQIntVec _typecheck; + SQObjectPtrVec _outervalues; + SQObjectPtr _env; + SQFUNCTION _function; + SQObjectPtr _name; +}; + + + +#endif //_SQCLOSURE_H_ diff --git a/src/3rdparty/squirrel/squirrel/sqcompiler.cpp b/src/3rdparty/squirrel/squirrel/sqcompiler.cpp new file mode 100644 index 0000000..2cc5f3d --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqcompiler.cpp @@ -0,0 +1,1372 @@ +/* + * see copyright notice in squirrel.h + */ + +#include "../../../stdafx.h" + +#include +#include "sqpcheader.h" +#include +#include "sqopcodes.h" +#include "sqstring.h" +#include "sqfuncproto.h" +#include "sqcompiler.h" +#include "sqfuncstate.h" +#include "sqlexer.h" +#include "sqvm.h" +#include "sqtable.h" + +#include "../../../string_func.h" + +#include "../../../safeguards.h" + +#define DEREF_NO_DEREF -1 +#define DEREF_FIELD -2 + +SQInteger _last_stacksize; + +struct ExpState +{ + ExpState() + { + _deref = DEREF_NO_DEREF; + _freevar = false; + _class_or_delete = false; + _funcarg = false; + } + bool _class_or_delete; + bool _funcarg; + bool _freevar; + SQInteger _deref; +}; + +typedef sqvector ExpStateVec; + +#define _exst (_expstates.top()) + +#define BEGIN_BREAKBLE_BLOCK() SQInteger __nbreaks__=_fs->_unresolvedbreaks.size(); \ + SQInteger __ncontinues__=_fs->_unresolvedcontinues.size(); \ + _fs->_breaktargets.push_back(0);_fs->_continuetargets.push_back(0); + +#define END_BREAKBLE_BLOCK(continue_target) {__nbreaks__=_fs->_unresolvedbreaks.size()-__nbreaks__; \ + __ncontinues__=_fs->_unresolvedcontinues.size()-__ncontinues__; \ + if(__ncontinues__>0)ResolveContinues(_fs,__ncontinues__,continue_target); \ + if(__nbreaks__>0)ResolveBreaks(_fs,__nbreaks__); \ + _fs->_breaktargets.pop_back();_fs->_continuetargets.pop_back();} + +class SQCompiler +{ +public: + SQCompiler(SQVM *v, SQLEXREADFUNC rg, SQUserPointer up, const SQChar* sourcename, bool raiseerror, bool lineinfo) : _lex(_ss(v), rg, up,ThrowError,this) + { + _vm=v; + _sourcename = SQString::Create(_ss(v), sourcename); + _lineinfo = lineinfo;_raiseerror = raiseerror; + } + NORETURN static void ThrowError(void *ud, const SQChar *s) { + SQCompiler *c = (SQCompiler *)ud; + c->Error(s); + } + NORETURN void Error(const SQChar *s, ...) + { + static SQChar temp[256]; + va_list vl; + va_start(vl, s); + vseprintf(temp, lastof(temp), s, vl); + va_end(vl); + throw temp; + } + void Lex(){ _token = _lex.Lex();} + void PushExpState(){ _expstates.push_back(ExpState()); } + bool IsDerefToken(SQInteger tok) + { + switch(tok){ + case '=': case '(': case TK_NEWSLOT: + case TK_MODEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MINUSEQ: case TK_PLUSEQ: case TK_PLUSPLUS: case TK_MINUSMINUS: return true; + } + return false; + } + ExpState PopExpState() + { + ExpState ret = _expstates.top(); + _expstates.pop_back(); + return ret; + } + SQObject Expect(SQInteger tok) + { + + if(_token != tok) { + if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) { + //ret = SQString::Create(_ss(_vm),"constructor"); + //do nothing + } + else { + const SQChar *etypename; + if(tok > 255) { + switch(tok) + { + case TK_IDENTIFIER: + etypename = "IDENTIFIER"; + break; + case TK_STRING_LITERAL: + etypename = "STRING_LITERAL"; + break; + case TK_INTEGER: + etypename = "INTEGER"; + break; + case TK_FLOAT: + etypename = "FLOAT"; + break; + default: + etypename = _lex.Tok2Str(tok); + } + Error("expected '%s'", etypename); + } + Error("expected '%c'", tok); + } + } + SQObjectPtr ret; + switch(tok) + { + case TK_IDENTIFIER: + ret = _fs->CreateString(_lex._svalue); + break; + case TK_STRING_LITERAL: + ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1); + break; + case TK_INTEGER: + ret = SQObjectPtr(_lex._nvalue); + break; + case TK_FLOAT: + ret = SQObjectPtr(_lex._fvalue); + break; + } + Lex(); + return ret; + } + bool IsEndOfStatement() { return ((_lex._prevtoken == '\n') || (_token == SQUIRREL_EOB) || (_token == '}') || (_token == ';')); } + void OptionalSemicolon() + { + if(_token == ';') { Lex(); return; } + if(!IsEndOfStatement()) { + Error("end of statement expected (; or lf)"); + } + } + void MoveIfCurrentTargetIsLocal() { + SQInteger trg = _fs->TopTarget(); + if(_fs->IsLocal(trg)) { + trg = _fs->PopTarget(); //no pops the target and move it + _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), trg); + } + } + bool Compile(SQObjectPtr &o) + { + _debugline = 1; + _debugop = 0; + + SQFuncState funcstate(_ss(_vm), NULL,ThrowError,this); + funcstate._name = SQString::Create(_ss(_vm), "main"); + _fs = &funcstate; + _fs->AddParameter(_fs->CreateString("this")); + _fs->_sourcename = _sourcename; + SQInteger stacksize = _fs->GetStackSize(); + try { + Lex(); + while(_token > 0){ + Statement(); + if(_lex._prevtoken != '}') OptionalSemicolon(); + } + CleanStack(stacksize); + _fs->AddLineInfos(_lex._currentline, _lineinfo, true); + _fs->AddInstruction(_OP_RETURN, 0xFF); + _fs->SetStackSize(0); + o =_fs->BuildProto(); +#ifdef _DEBUG_DUMP + _fs->Dump(_funcproto(o)); +#endif + return true; + } + catch (SQChar *compilererror) { + if(_raiseerror && _ss(_vm)->_compilererrorhandler) { + _ss(_vm)->_compilererrorhandler(_vm, compilererror, type(_sourcename) == OT_STRING?_stringval(_sourcename):"unknown", + _lex._currentline, _lex._currentcolumn); + } + _vm->_lasterror = SQString::Create(_ss(_vm), compilererror, -1); + return false; + } + } + void Statements() + { + while(_token != '}' && _token != TK_DEFAULT && _token != TK_CASE) { + Statement(); + if(_lex._prevtoken != '}' && _lex._prevtoken != ';') OptionalSemicolon(); + } + } + void Statement() + { + _fs->AddLineInfos(_lex._currentline, _lineinfo); + switch(_token){ + case ';': Lex(); break; + case TK_IF: IfStatement(); break; + case TK_WHILE: WhileStatement(); break; + case TK_DO: DoWhileStatement(); break; + case TK_FOR: ForStatement(); break; + case TK_FOREACH: ForEachStatement(); break; + case TK_SWITCH: SwitchStatement(); break; + case TK_LOCAL: LocalDeclStatement(); break; + case TK_RETURN: + case TK_YIELD: { + SQOpcode op; + if(_token == TK_RETURN) { + op = _OP_RETURN; + + } + else { + op = _OP_YIELD; + _fs->_bgenerator = true; + } + Lex(); + if(!IsEndOfStatement()) { + SQInteger retexp = _fs->GetCurrentPos()+1; + CommaExpr(); + if(op == _OP_RETURN && _fs->_traps > 0) + _fs->AddInstruction(_OP_POPTRAP, _fs->_traps, 0); + _fs->_returnexp = retexp; + _fs->AddInstruction(op, 1, _fs->PopTarget()); + } + else{ + if(op == _OP_RETURN && _fs->_traps > 0) + _fs->AddInstruction(_OP_POPTRAP, _fs->_traps ,0); + _fs->_returnexp = -1; + _fs->AddInstruction(op, 0xFF); + } + break;} + case TK_BREAK: + if(_fs->_breaktargets.size() <= 0)Error("'break' has to be in a loop block"); + if(_fs->_breaktargets.top() > 0){ + _fs->AddInstruction(_OP_POPTRAP, _fs->_breaktargets.top(), 0); + } + _fs->AddInstruction(_OP_SCOPE_END, _last_stacksize, _fs->GetStackSize()); + _fs->AddInstruction(_OP_JMP, 0, -1234); + _fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos()); + Lex(); + break; + case TK_CONTINUE: + if(_fs->_continuetargets.size() <= 0)Error("'continue' has to be in a loop block"); + if(_fs->_continuetargets.top() > 0) { + _fs->AddInstruction(_OP_POPTRAP, _fs->_continuetargets.top(), 0); + } + _fs->AddInstruction(_OP_SCOPE_END, _last_stacksize, _fs->GetStackSize()); + _fs->AddInstruction(_OP_JMP, 0, -1234); + _fs->_unresolvedcontinues.push_back(_fs->GetCurrentPos()); + Lex(); + break; + case TK_FUNCTION: + FunctionStatement(); + break; + case TK_CLASS: + ClassStatement(); + break; + case TK_ENUM: + EnumStatement(); + break; + case '{':{ + SQInteger stacksize = _fs->GetStackSize(); + Lex(); + Statements(); + Expect('}'); + _fs->AddInstruction(_OP_SCOPE_END, stacksize, _fs->GetStackSize()); + _fs->SetStackSize(stacksize); + } + break; + case TK_TRY: + TryCatchStatement(); + break; + case TK_THROW: + Lex(); + CommaExpr(); + _fs->AddInstruction(_OP_THROW, _fs->PopTarget()); + break; + case TK_CONST: + { + Lex(); + SQObject id = Expect(TK_IDENTIFIER); + Expect('='); + SQObject val = ExpectScalar(); + OptionalSemicolon(); + SQTable *enums = _table(_ss(_vm)->_consts); + SQObjectPtr strongid = id; + enums->NewSlot(strongid,SQObjectPtr(val)); + strongid.Null(); + } + break; + default: + CommaExpr(); + _fs->PopTarget(); + break; + } + _fs->SnoozeOpt(); + } + void EmitDerefOp(SQOpcode op) + { + SQInteger val = _fs->PopTarget(); + SQInteger key = _fs->PopTarget(); + SQInteger src = _fs->PopTarget(); + _fs->AddInstruction(op,_fs->PushTarget(),src,key,val); + } + void Emit2ArgsOP(SQOpcode op, SQInteger p3 = 0) + { + SQInteger p2 = _fs->PopTarget(); //src in OP_GET + SQInteger p1 = _fs->PopTarget(); //key in OP_GET + _fs->AddInstruction(op,_fs->PushTarget(), p1, p2, p3); + } + void EmitCompoundArith(SQInteger tok,bool deref) + { + SQInteger oper; + switch(tok){ + case TK_MINUSEQ: oper = '-'; break; + case TK_PLUSEQ: oper = '+'; break; + case TK_MULEQ: oper = '*'; break; + case TK_DIVEQ: oper = '/'; break; + case TK_MODEQ: oper = '%'; break; + default: oper = 0; //shut up compiler + assert(0); break; + }; + if(deref) { + SQInteger val = _fs->PopTarget(); + SQInteger key = _fs->PopTarget(); + SQInteger src = _fs->PopTarget(); + //mixes dest obj and source val in the arg1(hack?) + _fs->AddInstruction(_OP_COMPARITH,_fs->PushTarget(),(src<<16)|val,key,oper); + } + else { + Emit2ArgsOP(_OP_COMPARITHL, oper); + } + } + void CommaExpr() + { + for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr()) {} + } + ExpState Expression(bool funcarg = false) + { + PushExpState(); + _exst._class_or_delete = false; + _exst._funcarg = funcarg; + LogicalOrExp(); + switch(_token) { + case '=': + case TK_NEWSLOT: + case TK_MINUSEQ: + case TK_PLUSEQ: + case TK_MULEQ: + case TK_DIVEQ: + case TK_MODEQ: + { + SQInteger op = _token; + SQInteger ds = _exst._deref; + bool freevar = _exst._freevar; + if(ds == DEREF_NO_DEREF) Error("can't assign expression"); + Lex(); Expression(); + + switch(op){ + case TK_NEWSLOT: + if(freevar) Error("free variables cannot be modified"); + if(ds == DEREF_FIELD) + EmitDerefOp(_OP_NEWSLOT); + else //if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local + Error("can't 'create' a local slot"); + break; + case '=': //ASSIGN + if(freevar) Error("free variables cannot be modified"); + if(ds == DEREF_FIELD) + EmitDerefOp(_OP_SET); + else {//if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local + SQInteger p2 = _fs->PopTarget(); //src in OP_GET + SQInteger p1 = _fs->TopTarget(); //key in OP_GET + _fs->AddInstruction(_OP_MOVE, p1, p2); + } + break; + case TK_MINUSEQ: + case TK_PLUSEQ: + case TK_MULEQ: + case TK_DIVEQ: + case TK_MODEQ: + EmitCompoundArith(op,ds == DEREF_FIELD); + break; + } + } + break; + case '?': { + Lex(); + _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); + SQInteger jzpos = _fs->GetCurrentPos(); + SQInteger trg = _fs->PushTarget(); + Expression(); + SQInteger first_exp = _fs->PopTarget(); + if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp); + SQInteger endfirstexp = _fs->GetCurrentPos(); + _fs->AddInstruction(_OP_JMP, 0, 0); + Expect(':'); + SQInteger jmppos = _fs->GetCurrentPos(); + Expression(); + SQInteger second_exp = _fs->PopTarget(); + if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp); + _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos); + _fs->SetIntructionParam(jzpos, 1, endfirstexp - jzpos + 1); + _fs->SnoozeOpt(); + } + break; + } + return PopExpState(); + } + void BIN_EXP(SQOpcode op, void (SQCompiler::*f)(void),SQInteger op3 = 0) + { + Lex(); (this->*f)(); + SQInteger op1 = _fs->PopTarget();SQInteger op2 = _fs->PopTarget(); + _fs->AddInstruction(op, _fs->PushTarget(), op1, op2, op3); + } + void LogicalOrExp() + { + LogicalAndExp(); + if(_token == TK_OR) { + SQInteger first_exp = _fs->PopTarget(); + SQInteger trg = _fs->PushTarget(); + _fs->AddInstruction(_OP_OR, trg, 0, first_exp, 0); + SQInteger jpos = _fs->GetCurrentPos(); + if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp); + Lex(); LogicalOrExp(); + _fs->SnoozeOpt(); + SQInteger second_exp = _fs->PopTarget(); + if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp); + _fs->SnoozeOpt(); + _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos)); + } + } + void LogicalAndExp() + { + BitwiseOrExp(); + for(;;) switch(_token) { + case TK_AND: { + SQInteger first_exp = _fs->PopTarget(); + SQInteger trg = _fs->PushTarget(); + _fs->AddInstruction(_OP_AND, trg, 0, first_exp, 0); + SQInteger jpos = _fs->GetCurrentPos(); + if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp); + Lex(); LogicalAndExp(); + _fs->SnoozeOpt(); + SQInteger second_exp = _fs->PopTarget(); + if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp); + _fs->SnoozeOpt(); + _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos)); + break; + } + case TK_IN: BIN_EXP(_OP_EXISTS, &SQCompiler::BitwiseOrExp); break; + case TK_INSTANCEOF: BIN_EXP(_OP_INSTANCEOF, &SQCompiler::BitwiseOrExp); break; + default: + return; + } + } + void BitwiseOrExp() + { + BitwiseXorExp(); + for(;;) if(_token == '|') + {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseXorExp,BW_OR); + }else return; + } + void BitwiseXorExp() + { + BitwiseAndExp(); + for(;;) if(_token == '^') + {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseAndExp,BW_XOR); + }else return; + } + void BitwiseAndExp() + { + CompExp(); + for(;;) if(_token == '&') + {BIN_EXP(_OP_BITW, &SQCompiler::CompExp,BW_AND); + }else return; + } + void CompExp() + { + ShiftExp(); + for(;;) switch(_token) { + case TK_EQ: BIN_EXP(_OP_EQ, &SQCompiler::ShiftExp); break; + case '>': BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_G); break; + case '<': BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_L); break; + case TK_GE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_GE); break; + case TK_LE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_LE); break; + case TK_NE: BIN_EXP(_OP_NE, &SQCompiler::ShiftExp); break; + default: return; + } + } + void ShiftExp() + { + PlusExp(); + for(;;) switch(_token) { + case TK_USHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_USHIFTR); break; + case TK_SHIFTL: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTL); break; + case TK_SHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTR); break; + default: return; + } + } + void PlusExp() + { + MultExp(); + for(;;) switch(_token) { + case '+': case '-': + BIN_EXP(_OP_ARITH, &SQCompiler::MultExp,_token); break; + default: return; + } + } + + void MultExp() + { + PrefixedExpr(); + for(;;) switch(_token) { + case '*': case '/': case '%': + BIN_EXP(_OP_ARITH, &SQCompiler::PrefixedExpr,_token); break; + default: return; + } + } + //if 'pos' != -1 the previous variable is a local variable + void PrefixedExpr() + { + SQInteger pos = Factor(); + + for(;;) { + switch(_token) { + case '.': { + pos = -1; + Lex(); + if(_token == TK_PARENT) { + Lex(); + if(!NeedGet()) + Error("parent cannot be set"); + SQInteger src = _fs->PopTarget(); + _fs->AddInstruction(_OP_GETPARENT, _fs->PushTarget(), src); + } + else { + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER))); + if(NeedGet()) Emit2ArgsOP(_OP_GET); + } + _exst._deref = DEREF_FIELD; + _exst._freevar = false; + } + break; + case '[': + if(_lex._prevtoken == '\n') Error("cannot brake deref/or comma needed after [exp]=exp slot declaration"); + Lex(); Expression(); Expect(']'); + pos = -1; + if(NeedGet()) Emit2ArgsOP(_OP_GET); + _exst._deref = DEREF_FIELD; + _exst._freevar = false; + break; + case TK_MINUSMINUS: + case TK_PLUSPLUS: + if(_exst._deref != DEREF_NO_DEREF && !IsEndOfStatement()) { + SQInteger tok = _token; Lex(); + if(pos < 0) + Emit2ArgsOP(_OP_PINC,tok == TK_MINUSMINUS?-1:1); + else {//if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local + SQInteger src = _fs->PopTarget(); + _fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, tok == TK_MINUSMINUS?-1:1); + } + + } + return; + break; + case '(': + { + if(_exst._deref != DEREF_NO_DEREF) { + if(pos<0) { + SQInteger key = _fs->PopTarget(); //key + SQInteger table = _fs->PopTarget(); //table etc... + SQInteger closure = _fs->PushTarget(); + SQInteger ttarget = _fs->PushTarget(); + _fs->AddInstruction(_OP_PREPCALL, closure, key, table, ttarget); + } + else{ + _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0); + } + } + else + _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0); + _exst._deref = DEREF_NO_DEREF; + Lex(); + FunctionCallArgs(); + } + break; + default: return; + } + } + } + SQInteger Factor() + { + _exst._deref = DEREF_NO_DEREF; + switch(_token) + { + case TK_STRING_LITERAL: { + //SQObjectPtr id(SQString::Create(_ss(_vm), _lex._svalue,_lex._longstr.size()-1)); + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1))); + Lex(); + } + break; + case TK_VARGC: Lex(); _fs->AddInstruction(_OP_VARGC, _fs->PushTarget()); break; + case TK_VARGV: { Lex(); + Expect('['); + Expression(); + Expect(']'); + SQInteger src = _fs->PopTarget(); + _fs->AddInstruction(_OP_GETVARGV, _fs->PushTarget(), src); + } + break; + case TK_IDENTIFIER: + case TK_CONSTRUCTOR: + case TK_THIS:{ + _exst._freevar = false; + SQObject id; + SQObject constant; + switch(_token) { + case TK_IDENTIFIER: id = _fs->CreateString(_lex._svalue); break; + case TK_THIS: id = _fs->CreateString("this"); break; + case TK_CONSTRUCTOR: id = _fs->CreateString("constructor"); break; + } + SQInteger pos = -1; + Lex(); + if((pos = _fs->GetLocalVariable(id)) == -1) { + //checks if is a free variable + if((pos = _fs->GetOuterVariable(id)) != -1) { + _exst._deref = _fs->PushTarget(); + _fs->AddInstruction(_OP_LOADFREEVAR, _exst._deref ,pos); + _exst._freevar = true; + } + else if(_fs->IsConstant(id,constant)) { //line 634 + SQObjectPtr constval; + SQObject constid; + if(type(constant) == OT_TABLE) { + Expect('.'); constid = Expect(TK_IDENTIFIER); + if(!_table(constant)->Get(constid,constval)) { + constval.Null(); + Error("invalid constant [%s.%s]", _stringval(id),_stringval(constid)); + } + } + else { + constval = constant; + } + _exst._deref = _fs->PushTarget(); + SQObjectType ctype = type(constval); + if(ctype == OT_INTEGER && (_integer(constval) & (~0x7FFFFFFF)) == 0) { + _fs->AddInstruction(_OP_LOADINT, _exst._deref,_integer(constval)); + } + else if(ctype == OT_FLOAT && sizeof(SQFloat) == sizeof(SQInt32)) { + SQFloat f = _float(constval); + _fs->AddInstruction(_OP_LOADFLOAT, _exst._deref,*((SQInt32 *)&f)); + } + else { + _fs->AddInstruction(_OP_LOAD, _exst._deref, _fs->GetConstant(constval)); + } + + _exst._freevar = true; + } + else { + _fs->PushTarget(0); + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); + if(NeedGet()) Emit2ArgsOP(_OP_GET); + _exst._deref = DEREF_FIELD; + } + } + + else{ + _fs->PushTarget(pos); + _exst._deref = pos; + } + return _exst._deref; + } + break; + case TK_PARENT: Lex();_fs->AddInstruction(_OP_GETPARENT, _fs->PushTarget(), 0); break; + case TK_DOUBLE_COLON: // "::" + _fs->AddInstruction(_OP_LOADROOTTABLE, _fs->PushTarget()); + _exst._deref = DEREF_FIELD; + _token = '.'; //hack + return -1; + break; + case TK_NULL: + _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1); + Lex(); + break; + case TK_INTEGER: { + if((_lex._nvalue & (~0x7FFFFFFF)) == 0) { //does it fit in 32 bits? + _fs->AddInstruction(_OP_LOADINT, _fs->PushTarget(),_lex._nvalue); + } + else { + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._nvalue)); + } + Lex(); + } + break; + case TK_FLOAT: + if(sizeof(SQFloat) == sizeof(SQInt32)) { + _fs->AddInstruction(_OP_LOADFLOAT, _fs->PushTarget(),*((SQInt32 *)&_lex._fvalue)); + } + else { + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._fvalue)); + } + Lex(); + break; + case TK_TRUE: case TK_FALSE: + _fs->AddInstruction(_OP_LOADBOOL, _fs->PushTarget(),_token == TK_TRUE?1:0); + Lex(); + break; + case '[': { + _fs->AddInstruction(_OP_NEWARRAY, _fs->PushTarget()); + SQInteger apos = _fs->GetCurrentPos(),key = 0; + Lex(); + while(_token != ']') { + Expression(); + if(_token == ',') Lex(); + SQInteger val = _fs->PopTarget(); + SQInteger array = _fs->TopTarget(); + _fs->AddInstruction(_OP_APPENDARRAY, array, val); + key++; + } + _fs->SetIntructionParam(apos, 1, key); + Lex(); + } + break; + case '{':{ + _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); + Lex();ParseTableOrClass(','); + } + break; + case TK_FUNCTION: FunctionExp(_token);break; + case TK_CLASS: Lex(); ClassExp();break; + case '-': UnaryOP(_OP_NEG); break; + case '!': UnaryOP(_OP_NOT); break; + case '~': UnaryOP(_OP_BWNOT); break; + case TK_TYPEOF : UnaryOP(_OP_TYPEOF); break; + case TK_RESUME : UnaryOP(_OP_RESUME); break; + case TK_CLONE : UnaryOP(_OP_CLONE); break; + case TK_MINUSMINUS : + case TK_PLUSPLUS :PrefixIncDec(_token); break; + case TK_DELETE : DeleteExpr(); break; + case TK_DELEGATE : DelegateExpr(); break; + case '(': Lex(); CommaExpr(); Expect(')'); + break; + default: Error("expression expected"); + } + return -1; + } + void UnaryOP(SQOpcode op) + { + Lex(); PrefixedExpr(); + SQInteger src = _fs->PopTarget(); + _fs->AddInstruction(op, _fs->PushTarget(), src); + } + bool NeedGet() + { + switch(_token) { + case '=': case '(': case TK_NEWSLOT: case TK_PLUSPLUS: case TK_MINUSMINUS: + case TK_PLUSEQ: case TK_MINUSEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MODEQ: + return false; + } + return (!_exst._class_or_delete) || (_exst._class_or_delete && (_token == '.' || _token == '[')); + } + + void FunctionCallArgs() + { + SQInteger nargs = 1;//this + while(_token != ')') { + Expression(true); + MoveIfCurrentTargetIsLocal(); + nargs++; + if(_token == ','){ + Lex(); + if(_token == ')') Error("expression expected, found ')'"); + } + } + Lex(); + for(SQInteger i = 0; i < (nargs - 1); i++) _fs->PopTarget(); + SQInteger stackbase = _fs->PopTarget(); + SQInteger closure = _fs->PopTarget(); + _fs->AddInstruction(_OP_CALL, _fs->PushTarget(), closure, stackbase, nargs); + } + void ParseTableOrClass(SQInteger separator,SQInteger terminator = '}') + { + SQInteger tpos = _fs->GetCurrentPos(),nkeys = 0; + + while(_token != terminator) { + bool hasattrs = false; + bool isstatic = false; + //check if is an attribute + if(separator == ';') { + if(_token == TK_ATTR_OPEN) { + _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); Lex(); + ParseTableOrClass(',',TK_ATTR_CLOSE); + hasattrs = true; + } + if(_token == TK_STATIC) { + isstatic = true; + Lex(); + } + } + switch(_token) { + case TK_FUNCTION: + case TK_CONSTRUCTOR:{ + SQInteger tk = _token; + Lex(); + SQObject id = tk == TK_FUNCTION ? Expect(TK_IDENTIFIER) : _fs->CreateString("constructor"); + Expect('('); + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); + CreateFunction(id); + _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0); + } + break; + case '[': + Lex(); CommaExpr(); Expect(']'); + Expect('='); Expression(); + break; + default : + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER))); + Expect('='); Expression(); + } + + if(_token == separator) Lex();//optional comma/semicolon + nkeys++; + SQInteger val = _fs->PopTarget(); + SQInteger key = _fs->PopTarget(); + SQInteger attrs = hasattrs ? _fs->PopTarget():-1; + assert((hasattrs && attrs == key-1) || !hasattrs); + unsigned char flags = (hasattrs?NEW_SLOT_ATTRIBUTES_FLAG:0)|(isstatic?NEW_SLOT_STATIC_FLAG:0); + SQInteger table = _fs->TopTarget(); //<AddInstruction(_OP_NEWSLOTA, flags, table, key, val); + //_fs->PopTarget(); + } + if(separator == ',') //hack recognizes a table from the separator + _fs->SetIntructionParam(tpos, 1, nkeys); + Lex(); + } + void LocalDeclStatement() + { + SQObject varname; + do { + Lex(); varname = Expect(TK_IDENTIFIER); + if(_token == '=') { + Lex(); Expression(); + SQInteger src = _fs->PopTarget(); + SQInteger dest = _fs->PushTarget(); + if(dest != src) _fs->AddInstruction(_OP_MOVE, dest, src); + } + else{ + _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1); + } + _fs->PopTarget(); + _fs->PushLocalVariable(varname); + + } while(_token == ','); + } + void IfStatement() + { + SQInteger jmppos; + bool haselse = false; + Lex(); Expect('('); CommaExpr(); Expect(')'); + _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); + SQInteger jnepos = _fs->GetCurrentPos(); + SQInteger stacksize = _fs->GetStackSize(); + + Statement(); + // + if(_token != '}' && _token != TK_ELSE) OptionalSemicolon(); + + CleanStack(stacksize); + SQInteger endifblock = _fs->GetCurrentPos(); + if(_token == TK_ELSE){ + haselse = true; + stacksize = _fs->GetStackSize(); + _fs->AddInstruction(_OP_JMP); + jmppos = _fs->GetCurrentPos(); + Lex(); + Statement(); OptionalSemicolon(); + CleanStack(stacksize); + _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos); + } + _fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0)); + } + void WhileStatement() + { + SQInteger jzpos, jmppos; + SQInteger stacksize = _fs->GetStackSize(); + jmppos = _fs->GetCurrentPos(); + Lex(); Expect('('); CommaExpr(); Expect(')'); + + BEGIN_BREAKBLE_BLOCK(); + _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); + jzpos = _fs->GetCurrentPos(); + stacksize = _fs->GetStackSize(); + _last_stacksize = _fs->GetStackSize(); + + Statement(); + + CleanStack(stacksize); + _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1); + _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos); + + END_BREAKBLE_BLOCK(jmppos); + } + void DoWhileStatement() + { + Lex(); + SQInteger jzpos = _fs->GetCurrentPos(); + SQInteger stacksize = _fs->GetStackSize(); + BEGIN_BREAKBLE_BLOCK() + _last_stacksize = _fs->GetStackSize(); + Statement(); + CleanStack(stacksize); + _fs->AddLineInfos(_lex._currentline, _lineinfo, true); + Expect(TK_WHILE); + SQInteger continuetrg = _fs->GetCurrentPos(); + Expect('('); CommaExpr(); Expect(')'); + _fs->AddInstruction(_OP_JNZ, _fs->PopTarget(), jzpos - _fs->GetCurrentPos() - 1); + END_BREAKBLE_BLOCK(continuetrg); + } + void ForStatement() + { + Lex(); + SQInteger stacksize = _fs->GetStackSize(); + Expect('('); + if(_token == TK_LOCAL) LocalDeclStatement(); + else if(_token != ';'){ + CommaExpr(); + _fs->PopTarget(); + } + Expect(';'); + _fs->SnoozeOpt(); + SQInteger jmppos = _fs->GetCurrentPos(); + SQInteger jzpos = -1; + if(_token != ';') { CommaExpr(); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); jzpos = _fs->GetCurrentPos(); } + Expect(';'); + _fs->SnoozeOpt(); + SQInteger expstart = _fs->GetCurrentPos() + 1; + if(_token != ')') { + CommaExpr(); + _fs->PopTarget(); + } + Expect(')'); + _fs->SnoozeOpt(); + SQInteger expend = _fs->GetCurrentPos(); + SQInteger expsize = (expend - expstart) + 1; + SQInstructionVec exp; + if(expsize > 0) { + for(SQInteger i = 0; i < expsize; i++) + exp.push_back(_fs->GetInstruction(expstart + i)); + _fs->PopInstructions(expsize); + } + BEGIN_BREAKBLE_BLOCK() + _last_stacksize = _fs->GetStackSize(); + Statement(); + SQInteger continuetrg = _fs->GetCurrentPos(); + if(expsize > 0) { + for(SQInteger i = 0; i < expsize; i++) + _fs->AddInstruction(exp[i]); + } + _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0); + if(jzpos> 0) _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos); + CleanStack(stacksize); + + END_BREAKBLE_BLOCK(continuetrg); + } + void ForEachStatement() + { + SQObject idxname, valname; + Lex(); Expect('('); valname = Expect(TK_IDENTIFIER); + if(_token == ',') { + idxname = valname; + Lex(); valname = Expect(TK_IDENTIFIER); + } + else{ + idxname = _fs->CreateString("@INDEX@"); + } + Expect(TK_IN); + + //save the stack size + SQInteger stacksize = _fs->GetStackSize(); + //put the table in the stack(evaluate the table expression) + Expression(); Expect(')'); + SQInteger container = _fs->TopTarget(); + //push the index local var + SQInteger indexpos = _fs->PushLocalVariable(idxname); + _fs->AddInstruction(_OP_LOADNULLS, indexpos,1); + //push the value local var + SQInteger valuepos = _fs->PushLocalVariable(valname); + _fs->AddInstruction(_OP_LOADNULLS, valuepos,1); + //push reference index + SQInteger itrpos = _fs->PushLocalVariable(_fs->CreateString("@ITERATOR@")); //use invalid id to make it inaccessible + _fs->AddInstruction(_OP_LOADNULLS, itrpos,1); + SQInteger jmppos = _fs->GetCurrentPos(); + _fs->AddInstruction(_OP_FOREACH, container, 0, indexpos); + SQInteger foreachpos = _fs->GetCurrentPos(); + _fs->AddInstruction(_OP_POSTFOREACH, container, 0, indexpos); + //generate the statement code + BEGIN_BREAKBLE_BLOCK() + _last_stacksize = _fs->GetStackSize(); + Statement(); + _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1); + _fs->SetIntructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos); + _fs->SetIntructionParam(foreachpos + 1, 1, _fs->GetCurrentPos() - foreachpos); + //restore the local variable stack(remove index,val and ref idx) + CleanStack(stacksize); + END_BREAKBLE_BLOCK(foreachpos - 1); + } + void SwitchStatement() + { + Lex(); Expect('('); CommaExpr(); Expect(')'); + Expect('{'); + SQInteger expr = _fs->TopTarget(); + bool bfirst = true; + SQInteger tonextcondjmp = -1; + SQInteger skipcondjmp = -1; + SQInteger __nbreaks__ = _fs->_unresolvedbreaks.size(); + _fs->_breaktargets.push_back(0); + while(_token == TK_CASE) { + //_fs->AddLineInfos(_lex._currentline, _lineinfo); think about this one + if(!bfirst) { + _fs->AddInstruction(_OP_JMP, 0, 0); + skipcondjmp = _fs->GetCurrentPos(); + _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp); + } + //condition + Lex(); Expression(); Expect(':'); + SQInteger trg = _fs->PopTarget(); + _fs->AddInstruction(_OP_EQ, trg, trg, expr); + _fs->AddInstruction(_OP_JZ, trg, 0); + //end condition + if(skipcondjmp != -1) { + _fs->SetIntructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp)); + } + tonextcondjmp = _fs->GetCurrentPos(); + SQInteger stacksize = _fs->GetStackSize(); + _last_stacksize = _fs->GetStackSize(); + Statements(); + _fs->SetStackSize(stacksize); + bfirst = false; + } + if(tonextcondjmp != -1) + _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp); + if(_token == TK_DEFAULT) { + // _fs->AddLineInfos(_lex._currentline, _lineinfo); + Lex(); Expect(':'); + SQInteger stacksize = _fs->GetStackSize(); + _last_stacksize = _fs->GetStackSize(); + Statements(); + _fs->SetStackSize(stacksize); + } + Expect('}'); + _fs->PopTarget(); + __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__; + if(__nbreaks__ > 0)ResolveBreaks(_fs, __nbreaks__); + _fs->_breaktargets.pop_back(); + + } + void FunctionStatement() + { + SQObject id; + Lex(); id = Expect(TK_IDENTIFIER); + _fs->PushTarget(0); + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); + if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET); + + while(_token == TK_DOUBLE_COLON) { + Lex(); + id = Expect(TK_IDENTIFIER); + _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); + if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET); + } + Expect('('); + CreateFunction(id); + _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0); + EmitDerefOp(_OP_NEWSLOT); + _fs->PopTarget(); + } + void ClassStatement() + { + ExpState es; + Lex(); PushExpState(); + _exst._class_or_delete = true; + _exst._funcarg = false; + PrefixedExpr(); + es = PopExpState(); + if(es._deref == DEREF_NO_DEREF) Error("invalid class name"); + if(es._deref == DEREF_FIELD) { + ClassExp(); + EmitDerefOp(_OP_NEWSLOT); + _fs->PopTarget(); + } + else Error("cannot create a class in a local with the syntax(class )"); + } + SQObject ExpectScalar() + { + SQObject val; + switch(_token) { + case TK_INTEGER: + val._type = OT_INTEGER; + val._unVal.nInteger = _lex._nvalue; + break; + case TK_FLOAT: + val._type = OT_FLOAT; + val._unVal.fFloat = _lex._fvalue; + break; + case TK_STRING_LITERAL: + val = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1); + break; + case '-': + Lex(); + switch(_token) + { + case TK_INTEGER: + val._type = OT_INTEGER; + val._unVal.nInteger = -_lex._nvalue; + break; + case TK_FLOAT: + val._type = OT_FLOAT; + val._unVal.fFloat = -_lex._fvalue; + break; + default: + Error("scalar expected : integer,float"); + val._type = OT_NULL; // Silent compile-warning + } + break; + default: + Error("scalar expected : integer,float or string"); + val._type = OT_NULL; // Silent compile-warning + } + Lex(); + return val; + } + void EnumStatement() + { + + Lex(); + SQObject id = Expect(TK_IDENTIFIER); + Expect('{'); + + SQObject table = _fs->CreateTable(); + SQInteger nval = 0; + while(_token != '}') { + SQObject key = Expect(TK_IDENTIFIER); + SQObject val; + if(_token == '=') { + Lex(); + val = ExpectScalar(); + } + else { + val._type = OT_INTEGER; + val._unVal.nInteger = nval++; + } + _table(table)->NewSlot(SQObjectPtr(key),SQObjectPtr(val)); + if(_token == ',') Lex(); + } + SQTable *enums = _table(_ss(_vm)->_consts); + SQObjectPtr strongid = id; + /*SQObjectPtr dummy; + if(enums->Get(strongid,dummy)) { + dummy.Null(); strongid.Null(); + Error("enumeration already exists"); + }*/ + enums->NewSlot(SQObjectPtr(strongid),SQObjectPtr(table)); + strongid.Null(); + Lex(); + + } + void TryCatchStatement() + { + SQObject exid; + Lex(); + _fs->AddInstruction(_OP_PUSHTRAP,0,0); + _fs->_traps++; + if(_fs->_breaktargets.size()) _fs->_breaktargets.top()++; + if(_fs->_continuetargets.size()) _fs->_continuetargets.top()++; + SQInteger trappos = _fs->GetCurrentPos(); + Statement(); + _fs->_traps--; + _fs->AddInstruction(_OP_POPTRAP, 1, 0); + if(_fs->_breaktargets.size()) _fs->_breaktargets.top()--; + if(_fs->_continuetargets.size()) _fs->_continuetargets.top()--; + _fs->AddInstruction(_OP_JMP, 0, 0); + SQInteger jmppos = _fs->GetCurrentPos(); + _fs->SetIntructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos)); + Expect(TK_CATCH); Expect('('); exid = Expect(TK_IDENTIFIER); Expect(')'); + SQInteger stacksize = _fs->GetStackSize(); + SQInteger ex_target = _fs->PushLocalVariable(exid); + _fs->SetIntructionParam(trappos, 0, ex_target); + Statement(); + _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0); + CleanStack(stacksize); + } + void FunctionExp(SQInteger ftype) + { + Lex(); Expect('('); + CreateFunction(_null_); + _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1); + } + void ClassExp() + { + SQInteger base = -1; + SQInteger attrs = -1; + if(_token == TK_EXTENDS) { + Lex(); Expression(); + base = _fs->TopTarget(); + } + if(_token == TK_ATTR_OPEN) { + Lex(); + _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); + ParseTableOrClass(',',TK_ATTR_CLOSE); + attrs = _fs->TopTarget(); + } + Expect('{'); + if(attrs != -1) _fs->PopTarget(); + if(base != -1) _fs->PopTarget(); + _fs->AddInstruction(_OP_CLASS, _fs->PushTarget(), base, attrs); + ParseTableOrClass(';'); + } + void DelegateExpr() + { + Lex(); CommaExpr(); + Expect(':'); + CommaExpr(); + SQInteger table = _fs->PopTarget(), delegate = _fs->PopTarget(); + _fs->AddInstruction(_OP_DELEGATE, _fs->PushTarget(), table, delegate); + } + void DeleteExpr() + { + ExpState es; + Lex(); PushExpState(); + _exst._class_or_delete = true; + _exst._funcarg = false; + PrefixedExpr(); + es = PopExpState(); + if(es._deref == DEREF_NO_DEREF) Error("can't delete an expression"); + if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_DELETE); + else Error("cannot delete a local"); + } + void PrefixIncDec(SQInteger token) + { + ExpState es; + Lex(); PushExpState(); + _exst._class_or_delete = true; + _exst._funcarg = false; + PrefixedExpr(); + es = PopExpState(); + if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_INC,token == TK_MINUSMINUS?-1:1); + else { + SQInteger src = _fs->PopTarget(); + _fs->AddInstruction(_OP_INCL, _fs->PushTarget(), src, 0, token == TK_MINUSMINUS?-1:1); + } + } + void CreateFunction(SQObject &name) + { + + SQFuncState *funcstate = _fs->PushChildState(_ss(_vm)); + funcstate->_name = name; + SQObject paramname; + funcstate->AddParameter(_fs->CreateString("this")); + funcstate->_sourcename = _sourcename; + SQInteger defparams = 0; + while(_token!=')') { + if(_token == TK_VARPARAMS) { + if(defparams > 0) Error("function with default parameters cannot have variable number of parameters"); + funcstate->_varparams = true; + Lex(); + if(_token != ')') Error("expected ')'"); + break; + } + else { + paramname = Expect(TK_IDENTIFIER); + funcstate->AddParameter(paramname); + if(_token == '=') { + Lex(); + Expression(); + funcstate->AddDefaultParam(_fs->TopTarget()); + defparams++; + } + else { + if(defparams > 0) Error("expected '='"); + } + if(_token == ',') Lex(); + else if(_token != ')') Error("expected ')' or ','"); + } + } + Expect(')'); + for(SQInteger n = 0; n < defparams; n++) { + _fs->PopTarget(); + } + //outer values + if(_token == ':') { + Lex(); Expect('('); + while(_token != ')') { + paramname = Expect(TK_IDENTIFIER); + //outers are treated as implicit local variables + funcstate->AddOuterValue(paramname); + if(_token == ',') Lex(); + else if(_token != ')') Error("expected ')' or ','"); + } + Lex(); + } + + SQFuncState *currchunk = _fs; + _fs = funcstate; + Statement(); + funcstate->AddLineInfos(_lex._prevtoken == '\n'?_lex._lasttokenline:_lex._currentline, _lineinfo, true); + funcstate->AddInstruction(_OP_RETURN, -1); + funcstate->SetStackSize(0); + //_fs->->_stacksize = _fs->_stacksize; + SQFunctionProto *func = funcstate->BuildProto(); +#ifdef _DEBUG_DUMP + funcstate->Dump(func); +#endif + _fs = currchunk; + _fs->_functions.push_back(func); + _fs->PopChildState(); + } + void CleanStack(SQInteger stacksize) + { + if(_fs->GetStackSize() != stacksize) + _fs->SetStackSize(stacksize); + } + void ResolveBreaks(SQFuncState *funcstate, SQInteger ntoresolve) + { + while(ntoresolve > 0) { + SQInteger pos = funcstate->_unresolvedbreaks.back(); + funcstate->_unresolvedbreaks.pop_back(); + //set the jmp instruction + funcstate->SetIntructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0); + ntoresolve--; + } + } + void ResolveContinues(SQFuncState *funcstate, SQInteger ntoresolve, SQInteger targetpos) + { + while(ntoresolve > 0) { + SQInteger pos = funcstate->_unresolvedcontinues.back(); + funcstate->_unresolvedcontinues.pop_back(); + //set the jmp instruction + funcstate->SetIntructionParams(pos, 0, targetpos - pos, 0); + ntoresolve--; + } + } +private: + SQInteger _token; + SQFuncState *_fs; + SQObjectPtr _sourcename; + SQLexer _lex; + bool _lineinfo; + bool _raiseerror; + SQInteger _debugline; + SQInteger _debugop; + ExpStateVec _expstates; + SQVM *_vm; +}; + +bool Compile(SQVM *vm,SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo) +{ + SQCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo); + return p.Compile(out); +} diff --git a/src/3rdparty/squirrel/squirrel/sqcompiler.h b/src/3rdparty/squirrel/squirrel/sqcompiler.h new file mode 100644 index 0000000..b299173 --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqcompiler.h @@ -0,0 +1,82 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQCOMPILER_H_ +#define _SQCOMPILER_H_ + +struct SQVM; + +#define TK_IDENTIFIER 258 +#define TK_STRING_LITERAL 259 +#define TK_INTEGER 260 +#define TK_FLOAT 261 +#define TK_DELEGATE 262 +#define TK_DELETE 263 +#define TK_EQ 264 +#define TK_NE 265 +#define TK_LE 266 +#define TK_GE 267 +#define TK_SWITCH 268 +#define TK_ARROW 269 +#define TK_AND 270 +#define TK_OR 271 +#define TK_IF 272 +#define TK_ELSE 273 +#define TK_WHILE 274 +#define TK_BREAK 275 +#define TK_FOR 276 +#define TK_DO 277 +#define TK_NULL 278 +#define TK_FOREACH 279 +#define TK_IN 280 +#define TK_NEWSLOT 281 +#define TK_MODULO 282 +#define TK_LOCAL 283 +#define TK_CLONE 284 +#define TK_FUNCTION 285 +#define TK_RETURN 286 +#define TK_TYPEOF 287 +#define TK_UMINUS 288 +#define TK_PLUSEQ 289 +#define TK_MINUSEQ 290 +#define TK_CONTINUE 291 +#define TK_YIELD 292 +#define TK_TRY 293 +#define TK_CATCH 294 +#define TK_THROW 295 +#define TK_SHIFTL 296 +#define TK_SHIFTR 297 +#define TK_RESUME 298 +#define TK_DOUBLE_COLON 299 +#define TK_CASE 300 +#define TK_DEFAULT 301 +#define TK_THIS 302 +#define TK_PLUSPLUS 303 +#define TK_MINUSMINUS 304 +#define TK_PARENT 305 +#define TK_USHIFTR 306 +#define TK_CLASS 307 +#define TK_EXTENDS 308 +#define TK_CONSTRUCTOR 310 +#define TK_INSTANCEOF 311 +#define TK_VARPARAMS 312 +#define TK_VARGC 313 +#define TK_VARGV 314 +#define TK_TRUE 315 +#define TK_FALSE 316 +#define TK_MULEQ 317 +#define TK_DIVEQ 318 +#define TK_MODEQ 319 +#define TK_ATTR_OPEN 320 +#define TK_ATTR_CLOSE 321 +#define TK_STATIC 322 +#define TK_ENUM 323 +#define TK_CONST 324 + +/* MSVC doesn't like NORETURN for function prototypes, but we kinda need it for GCC. */ +#if defined(_MSC_VER) +typedef void(*CompilerErrorFunc)(void *ud, const SQChar *s); +#else +typedef NORETURN void(*CompilerErrorFunc)(void *ud, const SQChar *s); +#endif + +bool Compile(SQVM *vm, SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo); +#endif //_SQCOMPILER_H_ diff --git a/src/3rdparty/squirrel/squirrel/sqdebug.cpp b/src/3rdparty/squirrel/squirrel/sqdebug.cpp new file mode 100644 index 0000000..74272e4 --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqdebug.cpp @@ -0,0 +1,126 @@ +/* + * see copyright notice in squirrel.h + */ + +#include "../../../stdafx.h" + +#include +#include "sqpcheader.h" +#include "sqvm.h" +#include "sqfuncproto.h" +#include "sqclosure.h" +#include "sqstring.h" + +#include "../../../core/alloc_func.hpp" +#include "../../../string_func.h" + +#include "../../../safeguards.h" + +SQRESULT sq_getfunctioninfo(HSQUIRRELVM v,SQInteger level,SQFunctionInfo *fi) +{ + SQInteger cssize = v->_callsstacksize; + if (cssize > level) { + SQVM::CallInfo &ci = v->_callsstack[cssize-level-1]; + if(sq_isclosure(ci._closure)) { + SQClosure *c = _closure(ci._closure); + SQFunctionProto *proto = _funcproto(c->_function); + fi->funcid = proto; + fi->name = type(proto->_name) == OT_STRING?_stringval(proto->_name):"unknown"; + fi->source = type(proto->_name) == OT_STRING?_stringval(proto->_sourcename):"unknown"; + return SQ_OK; + } + } + return sq_throwerror(v,"the object is not a closure"); +} + +SQRESULT sq_stackinfos(HSQUIRRELVM v, SQInteger level, SQStackInfos *si) +{ + SQInteger cssize = v->_callsstacksize; + if (cssize > level) { + memset(si, 0, sizeof(SQStackInfos)); + SQVM::CallInfo &ci = v->_callsstack[cssize-level-1]; + switch (type(ci._closure)) { + case OT_CLOSURE:{ + SQFunctionProto *func = _funcproto(_closure(ci._closure)->_function); + if (type(func->_name) == OT_STRING) + si->funcname = _stringval(func->_name); + if (type(func->_sourcename) == OT_STRING) + si->source = _stringval(func->_sourcename); + si->line = func->GetLine(ci._ip); + } + break; + case OT_NATIVECLOSURE: + si->source = "NATIVE"; + si->funcname = "unknown"; + if(type(_nativeclosure(ci._closure)->_name) == OT_STRING) + si->funcname = _stringval(_nativeclosure(ci._closure)->_name); + si->line = -1; + break; + default: break; //shutup compiler + } + return SQ_OK; + } + return SQ_ERROR; +} + +void SQVM::Raise_Error(const SQChar *s, ...) +{ + va_list vl; + va_start(vl, s); + size_t len = strlen(s)+(NUMBER_MAX_CHAR*2); + char *buffer = MallocT(len + 1); + vseprintf(buffer, buffer + len, s, vl); + va_end(vl); + _lasterror = SQString::Create(_ss(this),buffer,-1); + free(buffer); +} + +void SQVM::Raise_Error(SQObjectPtr &desc) +{ + _lasterror = desc; +} + +SQString *SQVM::PrintObjVal(const SQObject &o) +{ + char buf[NUMBER_MAX_CHAR+1]; + switch(type(o)) { + case OT_STRING: return _string(o); + case OT_INTEGER: + seprintf(buf, lastof(buf), OTTD_PRINTF64, _integer(o)); + return SQString::Create(_ss(this), buf); + case OT_FLOAT: + seprintf(buf, lastof(buf), "%.14g", _float(o)); + return SQString::Create(_ss(this), buf); + default: + return SQString::Create(_ss(this), GetTypeName(o)); + } +} + +void SQVM::Raise_IdxError(const SQObject &o) +{ + SQObjectPtr oval = PrintObjVal(o); + Raise_Error("the index '%.50s' does not exist", _stringval(oval)); +} + +void SQVM::Raise_CompareError(const SQObject &o1, const SQObject &o2) +{ + SQObjectPtr oval1 = PrintObjVal(o1), oval2 = PrintObjVal(o2); + Raise_Error("comparsion between '%.50s' and '%.50s'", _stringval(oval1), _stringval(oval2)); +} + + +void SQVM::Raise_ParamTypeError(SQInteger nparam,SQInteger typemask,SQInteger type) +{ + SQObjectPtr exptypes = SQString::Create(_ss(this), "", -1); + SQInteger found = 0; + for(SQInteger i=0; i<16; i++) + { + SQInteger mask = 0x00000001 << i; + if(typemask & (mask)) { + if(found>0) StringCat(exptypes,SQString::Create(_ss(this), "|", -1), exptypes); + found ++; + StringCat(exptypes,SQString::Create(_ss(this), IdType2Name((SQObjectType)mask), -1), exptypes); + } + } + Raise_Error("parameter %d has an invalid type '%s' ; expected: '%s'", nparam, IdType2Name((SQObjectType)type), _stringval(exptypes)); +} diff --git a/src/3rdparty/squirrel/squirrel/sqfuncproto.h b/src/3rdparty/squirrel/squirrel/sqfuncproto.h new file mode 100644 index 0000000..e58ccd2 --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqfuncproto.h @@ -0,0 +1,166 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQFUNCTION_H_ +#define _SQFUNCTION_H_ + +#include "sqopcodes.h" + +enum SQOuterType { + otLOCAL = 0, + otSYMBOL = 1, + otOUTER = 2, +}; + +struct SQOuterVar +{ + + SQOuterVar() : _type(otLOCAL) {} + SQOuterVar(const SQObjectPtr &name,const SQObjectPtr &src,SQOuterType t) + { + _name = name; + _src=src; + _type=t; + } + SQOuterVar(const SQOuterVar &ov) + { + _type=ov._type; + _src=ov._src; + _name=ov._name; + } + SQOuterType _type; + SQObjectPtr _name; + SQObjectPtr _src; +}; + +struct SQLocalVarInfo +{ + SQLocalVarInfo():_start_op(0),_end_op(0), _pos(0){} + SQLocalVarInfo(const SQLocalVarInfo &lvi) + { + _name=lvi._name; + _start_op=lvi._start_op; + _end_op=lvi._end_op; + _pos=lvi._pos; + } + SQObjectPtr _name; + SQUnsignedInteger _start_op; + SQUnsignedInteger _end_op; + SQUnsignedInteger _pos; +}; + +struct SQLineInfo { SQInteger _line;SQInteger _op; }; + +typedef sqvector SQOuterVarVec; +typedef sqvector SQLocalVarInfoVec; +typedef sqvector SQLineInfoVec; + +#define _FUNC_SIZE(ni,nl,nparams,nfuncs,nouters,nlineinf,localinf,defparams) (sizeof(SQFunctionProto) \ + +((ni-1)*sizeof(SQInstruction))+(nl*sizeof(SQObjectPtr)) \ + +(nparams*sizeof(SQObjectPtr))+(nfuncs*sizeof(SQObjectPtr)) \ + +(nouters*sizeof(SQOuterVar))+(nlineinf*sizeof(SQLineInfo)) \ + +(localinf*sizeof(SQLocalVarInfo))+(defparams*sizeof(SQInteger))) + +#define _CONSTRUCT_VECTOR(type,size,ptr) { \ + for(SQInteger n = 0; n < size; n++) { \ + new (&ptr[n]) type(); \ + } \ +} + +#define _DESTRUCT_VECTOR(type,size,ptr) { \ + for(SQInteger nl = 0; nl < size; nl++) { \ + ptr[nl].~type(); \ + } \ +} +struct SQFunctionProto : public SQRefCounted +{ +private: + SQFunctionProto(SQInteger ninstructions, + SQInteger nliterals,SQInteger nparameters, + SQInteger nfunctions,SQInteger noutervalues, + SQInteger nlineinfos,SQInteger nlocalvarinfos,SQInteger ndefaultparams) + { + _stacksize=0; + _bgenerator=false; + _varparams = false; + _ninstructions = ninstructions; + _literals = (SQObjectPtr*)&_instructions[ninstructions]; + _nliterals = nliterals; + _parameters = (SQObjectPtr*)&_literals[nliterals]; + _nparameters = nparameters; + _functions = (SQObjectPtr*)&_parameters[nparameters]; + _nfunctions = nfunctions; + _outervalues = (SQOuterVar*)&_functions[nfunctions]; + _noutervalues = noutervalues; + _lineinfos = (SQLineInfo *)&_outervalues[noutervalues]; + _nlineinfos = nlineinfos; + _localvarinfos = (SQLocalVarInfo *)&_lineinfos[nlineinfos]; + _nlocalvarinfos = nlocalvarinfos; + _defaultparams = (SQInteger *)&_localvarinfos[nlocalvarinfos]; + _ndefaultparams = ndefaultparams; + + _CONSTRUCT_VECTOR(SQObjectPtr,_nliterals,_literals); + _CONSTRUCT_VECTOR(SQObjectPtr,_nparameters,_parameters); + _CONSTRUCT_VECTOR(SQObjectPtr,_nfunctions,_functions); + _CONSTRUCT_VECTOR(SQOuterVar,_noutervalues,_outervalues); + //_CONSTRUCT_VECTOR(SQLineInfo,_nlineinfos,_lineinfos); //not required are 2 integers + _CONSTRUCT_VECTOR(SQLocalVarInfo,_nlocalvarinfos,_localvarinfos); + } +public: + static SQFunctionProto *Create(SQInteger ninstructions, + SQInteger nliterals,SQInteger nparameters, + SQInteger nfunctions,SQInteger noutervalues, + SQInteger nlineinfos,SQInteger nlocalvarinfos,SQInteger ndefaultparams) + { + SQFunctionProto *f; + //I compact the whole class and members in a single memory allocation + f = (SQFunctionProto *)sq_vm_malloc(_FUNC_SIZE(ninstructions,nliterals,nparameters,nfunctions,noutervalues,nlineinfos,nlocalvarinfos,ndefaultparams)); + new (f) SQFunctionProto(ninstructions, nliterals, nparameters, nfunctions, noutervalues, nlineinfos, nlocalvarinfos, ndefaultparams); + return f; + } + void Release(){ + _DESTRUCT_VECTOR(SQObjectPtr,_nliterals,_literals); + _DESTRUCT_VECTOR(SQObjectPtr,_nparameters,_parameters); + _DESTRUCT_VECTOR(SQObjectPtr,_nfunctions,_functions); + _DESTRUCT_VECTOR(SQOuterVar,_noutervalues,_outervalues); + //_DESTRUCT_VECTOR(SQLineInfo,_nlineinfos,_lineinfos); //not required are 2 integers + _DESTRUCT_VECTOR(SQLocalVarInfo,_nlocalvarinfos,_localvarinfos); + SQInteger size = _FUNC_SIZE(_ninstructions,_nliterals,_nparameters,_nfunctions,_noutervalues,_nlineinfos,_nlocalvarinfos,_ndefaultparams); + this->~SQFunctionProto(); + sq_vm_free(this,size); + } + const SQChar* GetLocal(SQVM *v,SQUnsignedInteger stackbase,SQUnsignedInteger nseq,SQUnsignedInteger nop); + SQInteger GetLine(SQInstruction *curr); + bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write); + static bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret); + + SQObjectPtr _sourcename; + SQObjectPtr _name; + SQInteger _stacksize; + bool _bgenerator; + bool _varparams; + + SQInteger _nlocalvarinfos; + SQLocalVarInfo *_localvarinfos; + + SQInteger _nlineinfos; + SQLineInfo *_lineinfos; + + SQInteger _nliterals; + SQObjectPtr *_literals; + + SQInteger _nparameters; + SQObjectPtr *_parameters; + + SQInteger _nfunctions; + SQObjectPtr *_functions; + + SQInteger _noutervalues; + SQOuterVar *_outervalues; + + SQInteger _ndefaultparams; + SQInteger *_defaultparams; + + SQInteger _ninstructions; + SQInstruction _instructions[1]; +}; + +#endif //_SQFUNCTION_H_ diff --git a/src/3rdparty/squirrel/squirrel/sqfuncstate.cpp b/src/3rdparty/squirrel/squirrel/sqfuncstate.cpp new file mode 100644 index 0000000..5415b56 --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqfuncstate.cpp @@ -0,0 +1,569 @@ +/* + * see copyright notice in squirrel.h + */ + +#include "../../../stdafx.h" + +#include "sqpcheader.h" +#include "sqcompiler.h" +#include "sqfuncproto.h" +#include "sqstring.h" +#include "sqtable.h" +#include "sqopcodes.h" +#include "sqfuncstate.h" + +#include "../../../safeguards.h" + +#ifdef _DEBUG_DUMP +SQInstructionDesc g_InstrDesc[]={ + {"_OP_LINE"}, + {"_OP_LOAD"}, + {"_OP_LOADINT"}, + {"_OP_LOADFLOAT"}, + {"_OP_DLOAD"}, + {"_OP_TAILCALL"}, + {"_OP_CALL"}, + {"_OP_PREPCALL"}, + {"_OP_PREPCALLK"}, + {"_OP_GETK"}, + {"_OP_MOVE"}, + {"_OP_NEWSLOT"}, + {"_OP_DELETE"}, + {"_OP_SET"}, + {"_OP_GET"}, + {"_OP_EQ"}, + {"_OP_NE"}, + {"_OP_ARITH"}, + {"_OP_BITW"}, + {"_OP_RETURN"}, + {"_OP_LOADNULLS"}, + {"_OP_LOADROOTTABLE"}, + {"_OP_LOADBOOL"}, + {"_OP_DMOVE"}, + {"_OP_JMP"}, + {"_OP_JNZ"}, + {"_OP_JZ"}, + {"_OP_LOADFREEVAR"}, + {"_OP_VARGC"}, + {"_OP_GETVARGV"}, + {"_OP_NEWTABLE"}, + {"_OP_NEWARRAY"}, + {"_OP_APPENDARRAY"}, + {"_OP_GETPARENT"}, + {"_OP_COMPARITH"}, + {"_OP_COMPARITHL"}, + {"_OP_INC"}, + {"_OP_INCL"}, + {"_OP_PINC"}, + {"_OP_PINCL"}, + {"_OP_CMP"}, + {"_OP_EXISTS"}, + {"_OP_INSTANCEOF"}, + {"_OP_AND"}, + {"_OP_OR"}, + {"_OP_NEG"}, + {"_OP_NOT"}, + {"_OP_BWNOT"}, + {"_OP_CLOSURE"}, + {"_OP_YIELD"}, + {"_OP_RESUME"}, + {"_OP_FOREACH"}, + {"_OP_POSTFOREACH"}, + {"_OP_DELEGATE"}, + {"_OP_CLONE"}, + {"_OP_TYPEOF"}, + {"_OP_PUSHTRAP"}, + {"_OP_POPTRAP"}, + {"_OP_THROW"}, + {"_OP_CLASS"}, + {"_OP_NEWSLOTA"}, + {"_OP_SCOPE_END"} +}; +#endif +void DumpLiteral(SQObjectPtr &o) +{ + switch(type(o)){ + case OT_STRING: printf("\"%s\"",_stringval(o));break; + case OT_FLOAT: printf("{%f}",_float(o));break; + case OT_INTEGER: printf("{" OTTD_PRINTF64 "}",_integer(o));break; + case OT_BOOL: printf("%s",_integer(o)?"true":"false");break; + default: printf("(%s %p)",GetTypeName(o),(void*)_rawval(o));break; break; //shut up compiler + } +} + +SQFuncState::SQFuncState(SQSharedState *ss,SQFuncState *parent,CompilerErrorFunc efunc,void *ed) +{ + _nliterals = 0; + _literals = SQTable::Create(ss,0); + _strings = SQTable::Create(ss,0); + _sharedstate = ss; + _lastline = 0; + _optimization = true; + _parent = parent; + _stacksize = 0; + _traps = 0; + _returnexp = 0; + _varparams = false; + _errfunc = efunc; + _errtarget = ed; + _bgenerator = false; + +} + +void SQFuncState::Error(const SQChar *err) +{ + _errfunc(_errtarget,err); +} + +#ifdef _DEBUG_DUMP +void SQFuncState::Dump(SQFunctionProto *func) +{ + SQUnsignedInteger n=0,i; + SQInteger si; + printf("SQInstruction sizeof %d\n",sizeof(SQInstruction)); + printf("SQObject sizeof %d\n",sizeof(SQObject)); + printf("--------------------------------------------------------------------\n"); + printf("*****FUNCTION [%s]\n",type(func->_name)==OT_STRING?_stringval(func->_name):"unknown"); + printf("-----LITERALS\n"); + SQObjectPtr refidx,key,val; + SQInteger idx; + SQObjectPtrVec templiterals; + templiterals.resize(_nliterals); + while((idx=_table(_literals)->Next(false,refidx,key,val))!=-1) { + refidx=idx; + templiterals[_integer(val)]=key; + } + for(i=0;i>\n"); + n=0; + for(i=0;i<_parameters.size();i++){ + printf("[%d] ",n); + DumpLiteral(_parameters[i]); + printf("\n"); + n++; + } + printf("-----LOCALS\n"); + for(si=0;si_nlocalvarinfos;si++){ + SQLocalVarInfo lvi=func->_localvarinfos[si]; + printf("[%d] %s \t%d %d\n",lvi._pos,_stringval(lvi._name),lvi._start_op,lvi._end_op); + n++; + } + printf("-----LINE INFO\n"); + for(i=0;i<_lineinfos.size();i++){ + SQLineInfo li=_lineinfos[i]; + printf("op [%d] line [%d] \n",li._op,li._line); + n++; + } + printf("-----dump\n"); + n=0; + for(i=0;i<_instructions.size();i++){ + SQInstruction &inst=_instructions[i]; + if(inst.op==_OP_LOAD || inst.op==_OP_DLOAD || inst.op==_OP_PREPCALLK || inst.op==_OP_GETK ){ + + SQInteger lidx = inst._arg1; + printf("[%03d] %15s %d ",n,g_InstrDesc[inst.op].name,inst._arg0); + if(lidx >= 0xFFFFFFFF) + printf("null"); + else { + SQInteger refidx; + SQObjectPtr val,key,refo; + while(((refidx=_table(_literals)->Next(false,refo,key,val))!= -1) && (_integer(val) != lidx)) { + refo = refidx; + } + DumpLiteral(key); + } + if(inst.op != _OP_DLOAD) { + printf(" %d %d \n",inst._arg2,inst._arg3); + } + else { + printf(" %d ",inst._arg2); + lidx = inst._arg3; + if(lidx >= 0xFFFFFFFF) + printf("null"); + else { + SQInteger refidx; + SQObjectPtr val,key,refo; + while(((refidx=_table(_literals)->Next(false,refo,key,val))!= -1) && (_integer(val) != lidx)) { + refo = refidx; + } + DumpLiteral(key); + printf("\n"); + } + } + } + else if(inst.op==_OP_LOADFLOAT) { + printf("[%03d] %15s %d %f %d %d\n",n,g_InstrDesc[inst.op].name,inst._arg0,*((SQFloat*)&inst._arg1),inst._arg2,inst._arg3); + } + else if(inst.op==_OP_ARITH){ + printf("[%03d] %15s %d %d %d %c\n",n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3); + } + else + printf("[%03d] %15s %d %d %d %d\n",n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3); + n++; + } + printf("-----\n"); + printf("stack size[%d]\n",func->_stacksize); + printf("--------------------------------------------------------------------\n\n"); +} +#endif + +SQInteger SQFuncState::GetNumericConstant(const SQInteger cons) +{ + return GetConstant(SQObjectPtr(cons)); +} + +SQInteger SQFuncState::GetNumericConstant(const SQFloat cons) +{ + return GetConstant(SQObjectPtr(cons)); +} + +SQInteger SQFuncState::GetConstant(const SQObject &cons) +{ + SQObjectPtr val; + if(!_table(_literals)->Get(cons,val)) + { + val = _nliterals; + _table(_literals)->NewSlot(cons,val); + _nliterals++; + if(_nliterals > MAX_LITERALS) { + val.Null(); + Error("internal compiler error: too many literals"); + } + } + return _integer(val); +} + +void SQFuncState::SetIntructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2,SQInteger arg3) +{ + _instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&arg0); + _instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&arg1); + _instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&arg2); + _instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&arg3); +} + +void SQFuncState::SetIntructionParam(SQInteger pos,SQInteger arg,SQInteger val) +{ + switch(arg){ + case 0:_instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&val);break; + case 1:case 4:_instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&val);break; + case 2:_instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&val);break; + case 3:_instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&val);break; + }; +} + +SQInteger SQFuncState::AllocStackPos() +{ + SQInteger npos=_vlocals.size(); + _vlocals.push_back(SQLocalVarInfo()); + if(_vlocals.size()>((SQUnsignedInteger)_stacksize)) { + if(_stacksize>MAX_FUNC_STACKSIZE) Error("internal compiler error: too many locals"); + _stacksize=_vlocals.size(); + } + return npos; +} + +SQInteger SQFuncState::PushTarget(SQInteger n) +{ + if(n!=-1){ + _targetstack.push_back(n); + return n; + } + n=AllocStackPos(); + _targetstack.push_back(n); + return n; +} + +SQInteger SQFuncState::GetUpTarget(SQInteger n){ + return _targetstack[((_targetstack.size()-1)-n)]; +} + +SQInteger SQFuncState::TopTarget(){ + return _targetstack.back(); +} +SQInteger SQFuncState::PopTarget() +{ + SQInteger npos=_targetstack.back(); + SQLocalVarInfo t=_vlocals[_targetstack.back()]; + if(type(t._name)==OT_NULL){ + _vlocals.pop_back(); + } + _targetstack.pop_back(); + return npos; +} + +SQInteger SQFuncState::GetStackSize() +{ + return _vlocals.size(); +} + +void SQFuncState::SetStackSize(SQInteger n) +{ + SQInteger size=_vlocals.size(); + while(size>n){ + size--; + SQLocalVarInfo lvi=_vlocals.back(); + if(type(lvi._name)!=OT_NULL){ + lvi._end_op=GetCurrentPos(); + _localvarinfos.push_back(lvi); + } + _vlocals.pop_back(); + } +} + +bool SQFuncState::IsConstant(const SQObject &name,SQObject &e) +{ + SQObjectPtr val; + if(_table(_sharedstate->_consts)->Get(name,val)) { + e = val; + return true; + } + return false; +} + +bool SQFuncState::IsLocal(SQUnsignedInteger stkpos) +{ + if(stkpos>=_vlocals.size())return false; + else if(type(_vlocals[stkpos]._name)!=OT_NULL)return true; + return false; +} + +SQInteger SQFuncState::PushLocalVariable(const SQObject &name) +{ + SQInteger pos=_vlocals.size(); + SQLocalVarInfo lvi; + lvi._name=name; + lvi._start_op=GetCurrentPos()+1; + lvi._pos=_vlocals.size(); + _vlocals.push_back(lvi); + if(_vlocals.size()>((SQUnsignedInteger)_stacksize))_stacksize=_vlocals.size(); + + return pos; +} + +SQInteger SQFuncState::GetLocalVariable(const SQObject &name) +{ + SQInteger locals=_vlocals.size(); + while(locals>=1){ + if(type(_vlocals[locals-1]._name)==OT_STRING && _string(_vlocals[locals-1]._name)==_string(name)){ + return locals-1; + } + locals--; + } + return -1; +} + +SQInteger SQFuncState::GetOuterVariable(const SQObject &name) +{ + SQInteger outers = _outervalues.size(); + for(SQInteger i = 0; iGetLocalVariable(name); + if(pos == -1) { + pos = _parent->GetOuterVariable(name); + if(pos != -1) { + _outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otOUTER)); //local + return; + } + } + else { + _outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otLOCAL)); //local + return; + } + } + _outervalues.push_back(SQOuterVar(name,name,otSYMBOL)); //global +} + +void SQFuncState::AddParameter(const SQObject &name) +{ + PushLocalVariable(name); + _parameters.push_back(name); +} + +void SQFuncState::AddLineInfos(SQInteger line,bool lineop,bool force) +{ + if(_lastline!=line || force){ + SQLineInfo li; + li._line=line;li._op=(GetCurrentPos()+1); + if(lineop)AddInstruction(_OP_LINE,0,line); + _lineinfos.push_back(li); + _lastline=line; + } +} + +void SQFuncState::AddInstruction(SQInstruction &i) +{ + SQInteger size = _instructions.size(); + if(size > 0 && _optimization){ //simple optimizer + SQInstruction &pi = _instructions[size-1];//previous instruction + switch(i.op) { + case _OP_RETURN: + if( _parent && i._arg0 != MAX_FUNC_STACKSIZE && pi.op == _OP_CALL && _returnexp < size-1) { + pi.op = _OP_TAILCALL; + } + break; + case _OP_GET: + if( pi.op == _OP_LOAD && pi._arg0 == i._arg2 && (!IsLocal(pi._arg0))){ + pi._arg2 = (unsigned char)i._arg1; + pi.op = _OP_GETK; + pi._arg0 = i._arg0; + + return; + } + break; + case _OP_PREPCALL: + if( pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){ + pi.op = _OP_PREPCALLK; + pi._arg0 = i._arg0; + pi._arg2 = i._arg2; + pi._arg3 = i._arg3; + return; + } + break; + case _OP_APPENDARRAY: + if(pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){ + pi.op = _OP_APPENDARRAY; + pi._arg0 = i._arg0; + pi._arg2 = MAX_FUNC_STACKSIZE; + pi._arg3 = MAX_FUNC_STACKSIZE; + return; + } + break; + case _OP_MOVE: + if((pi.op == _OP_GET || pi.op == _OP_ARITH || pi.op == _OP_BITW) && (pi._arg0 == i._arg1)) + { + pi._arg0 = i._arg0; + _optimization = false; + return; + } + + if(pi.op == _OP_MOVE) + { + pi.op = _OP_DMOVE; + pi._arg2 = i._arg0; + pi._arg3 = (unsigned char)i._arg1; + return; + } + break; + case _OP_LOAD: + if(pi.op == _OP_LOAD && i._arg1 < 256) { + pi.op = _OP_DLOAD; + pi._arg2 = i._arg0; + pi._arg3 = (unsigned char)i._arg1; + return; + } + break; + case _OP_EQ:case _OP_NE: + if(pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0) )) + { + pi.op = i.op; + pi._arg0 = i._arg0; + pi._arg2 = i._arg2; + pi._arg3 = MAX_FUNC_STACKSIZE; + return; + } + break; + case _OP_LOADNULLS: + if((pi.op == _OP_LOADNULLS && pi._arg0+pi._arg1 == i._arg0)) { + + pi._arg1 = pi._arg1 + 1; + pi.op = _OP_LOADNULLS; + return; + } + break; + case _OP_LINE: + if(pi.op == _OP_LINE) { + _instructions.pop_back(); + _lineinfos.pop_back(); + } + break; + } + } + _optimization = true; + _instructions.push_back(i); +} + +SQObject SQFuncState::CreateString(const SQChar *s,SQInteger len) +{ + SQObjectPtr ns(SQString::Create(_sharedstate,s,len)); + _table(_strings)->NewSlot(ns,(SQInteger)1); + return ns; +} + +SQObject SQFuncState::CreateTable() +{ + SQObjectPtr nt(SQTable::Create(_sharedstate,0)); + _table(_strings)->NewSlot(nt,(SQInteger)1); + return nt; +} + +SQFunctionProto *SQFuncState::BuildProto() +{ + SQFunctionProto *f=SQFunctionProto::Create(_instructions.size(), + _nliterals,_parameters.size(),_functions.size(),_outervalues.size(), + _lineinfos.size(),_localvarinfos.size(),_defaultparams.size()); + + SQObjectPtr refidx,key,val; + SQInteger idx; + + f->_stacksize = _stacksize; + f->_sourcename = _sourcename; + f->_bgenerator = _bgenerator; + f->_name = _name; + + while((idx=_table(_literals)->Next(false,refidx,key,val))!=-1) { + f->_literals[_integer(val)]=key; + refidx=idx; + } + + for(SQUnsignedInteger nf = 0; nf < _functions.size(); nf++) f->_functions[nf] = _functions[nf]; + for(SQUnsignedInteger np = 0; np < _parameters.size(); np++) f->_parameters[np] = _parameters[np]; + for(SQUnsignedInteger no = 0; no < _outervalues.size(); no++) f->_outervalues[no] = _outervalues[no]; + for(SQUnsignedInteger no = 0; no < _localvarinfos.size(); no++) f->_localvarinfos[no] = _localvarinfos[no]; + for(SQUnsignedInteger no = 0; no < _lineinfos.size(); no++) f->_lineinfos[no] = _lineinfos[no]; + for(SQUnsignedInteger no = 0; no < _defaultparams.size(); no++) f->_defaultparams[no] = _defaultparams[no]; + + memcpy(f->_instructions,&_instructions[0],(size_t)_instructions.size()*sizeof(SQInstruction)); + + f->_varparams = _varparams; + + return f; +} + +SQFuncState *SQFuncState::PushChildState(SQSharedState *ss) +{ + SQFuncState *child = (SQFuncState *)sq_malloc(sizeof(SQFuncState)); + new (child) SQFuncState(ss,this,_errfunc,_errtarget); + _childstates.push_back(child); + return child; +} + +void SQFuncState::PopChildState() +{ + SQFuncState *child = _childstates.back(); + sq_delete(child,SQFuncState); + _childstates.pop_back(); +} + +SQFuncState::~SQFuncState() +{ + while(_childstates.size() > 0) + { + PopChildState(); + } +} diff --git a/src/3rdparty/squirrel/squirrel/sqfuncstate.h b/src/3rdparty/squirrel/squirrel/sqfuncstate.h new file mode 100644 index 0000000..c0bf1e5 --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqfuncstate.h @@ -0,0 +1,85 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQFUNCSTATE_H_ +#define _SQFUNCSTATE_H_ +/////////////////////////////////// +#include "squtils.h" + +struct SQFuncState +{ + SQFuncState(SQSharedState *ss,SQFuncState *parent,CompilerErrorFunc efunc,void *ed); + ~SQFuncState(); +#ifdef _DEBUG_DUMP + void Dump(SQFunctionProto *func); +#endif + void Error(const SQChar *err); + SQFuncState *PushChildState(SQSharedState *ss); + void PopChildState(); + void AddInstruction(SQOpcode _op,SQInteger arg0=0,SQInteger arg1=0,SQInteger arg2=0,SQInteger arg3=0){SQInstruction i(_op,arg0,arg1,arg2,arg3);AddInstruction(i);} + void AddInstruction(SQInstruction &i); + void SetIntructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2=0,SQInteger arg3=0); + void SetIntructionParam(SQInteger pos,SQInteger arg,SQInteger val); + SQInstruction &GetInstruction(SQInteger pos){return _instructions[pos];} + void PopInstructions(SQInteger size){for(SQInteger i=0;i _childstates; + SQInteger GetConstant(const SQObject &cons); +private: + CompilerErrorFunc _errfunc; + void *_errtarget; +}; + + +#endif //_SQFUNCSTATE_H_ + diff --git a/src/3rdparty/squirrel/squirrel/sqlexer.cpp b/src/3rdparty/squirrel/squirrel/sqlexer.cpp new file mode 100644 index 0000000..77c487a --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqlexer.cpp @@ -0,0 +1,491 @@ +/* + * see copyright notice in squirrel.h + */ + +#include "../../../stdafx.h" + +#include "sqpcheader.h" +#include +#include "sqtable.h" +#include "sqstring.h" +#include "sqcompiler.h" +#include "sqlexer.h" + +#include "../../../string_func.h" + +#include "../../../safeguards.h" + +#define CUR_CHAR (_currdata) +#define RETURN_TOKEN(t) { _prevtoken = _curtoken; _curtoken = t; return t;} +#define IS_EOB() (CUR_CHAR <= SQUIRREL_EOB) +#define NEXT() {Next();_currentcolumn++;} +#define ADD_KEYWORD(key,id) _keywords->NewSlot( SQString::Create(ss, #key) ,SQInteger(id)) + +SQLexer::~SQLexer() +{ + _keywords->Release(); +} + +void SQLexer::APPEND_CHAR(WChar c) +{ + char buf[4]; + size_t chars = Utf8Encode(buf, c); + for (size_t i = 0; i < chars; i++) { + _longstr.push_back(buf[i]); + } +} + +SQLexer::SQLexer(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up,CompilerErrorFunc efunc,void *ed) +{ + _errfunc = efunc; + _errtarget = ed; + _sharedstate = ss; + _keywords = SQTable::Create(ss, 26); + ADD_KEYWORD(while, TK_WHILE); + ADD_KEYWORD(do, TK_DO); + ADD_KEYWORD(if, TK_IF); + ADD_KEYWORD(else, TK_ELSE); + ADD_KEYWORD(break, TK_BREAK); + ADD_KEYWORD(continue, TK_CONTINUE); + ADD_KEYWORD(return, TK_RETURN); + ADD_KEYWORD(null, TK_NULL); + ADD_KEYWORD(function, TK_FUNCTION); + ADD_KEYWORD(local, TK_LOCAL); + ADD_KEYWORD(for, TK_FOR); + ADD_KEYWORD(foreach, TK_FOREACH); + ADD_KEYWORD(in, TK_IN); + ADD_KEYWORD(typeof, TK_TYPEOF); + ADD_KEYWORD(delegate, TK_DELEGATE); + ADD_KEYWORD(delete, TK_DELETE); + ADD_KEYWORD(try, TK_TRY); + ADD_KEYWORD(catch, TK_CATCH); + ADD_KEYWORD(throw, TK_THROW); + ADD_KEYWORD(clone, TK_CLONE); + ADD_KEYWORD(yield, TK_YIELD); + ADD_KEYWORD(resume, TK_RESUME); + ADD_KEYWORD(switch, TK_SWITCH); + ADD_KEYWORD(case, TK_CASE); + ADD_KEYWORD(default, TK_DEFAULT); + ADD_KEYWORD(this, TK_THIS); + ADD_KEYWORD(parent,TK_PARENT); + ADD_KEYWORD(class,TK_CLASS); + ADD_KEYWORD(extends,TK_EXTENDS); + ADD_KEYWORD(constructor,TK_CONSTRUCTOR); + ADD_KEYWORD(instanceof,TK_INSTANCEOF); + ADD_KEYWORD(vargc,TK_VARGC); + ADD_KEYWORD(vargv,TK_VARGV); + ADD_KEYWORD(true,TK_TRUE); + ADD_KEYWORD(false,TK_FALSE); + ADD_KEYWORD(static,TK_STATIC); + ADD_KEYWORD(enum,TK_ENUM); + ADD_KEYWORD(const,TK_CONST); + + _readf = rg; + _up = up; + _lasttokenline = _currentline = 1; + _currentcolumn = 0; + _prevtoken = -1; + _curtoken = -1; + + _svalue = NULL; + _nvalue = 0; + _fvalue = 0; + + Next(); +} + +NORETURN void SQLexer::Error(const SQChar *err) +{ + _errfunc(_errtarget,err); +} + +void SQLexer::Next() +{ + WChar t = _readf(_up); + if(t > MAX_CHAR) Error("Invalid character"); + if(t != 0) { + _currdata = t; + return; + } + _currdata = SQUIRREL_EOB; +} + +const SQChar *SQLexer::Tok2Str(SQInteger tok) +{ + SQObjectPtr itr, key, val; + SQInteger nitr; + while((nitr = _keywords->Next(false,itr, key, val)) != -1) { + itr = (SQInteger)nitr; + if(((SQInteger)_integer(val)) == tok) + return _stringval(key); + } + return NULL; +} + +void SQLexer::LexBlockComment() +{ + bool done = false; + while(!done) { + switch(CUR_CHAR) { + case '*': { NEXT(); if(CUR_CHAR == '/') { done = true; NEXT(); }}; continue; + case '\n': _currentline++; NEXT(); continue; + case SQUIRREL_EOB: Error("missing \"*/\" in comment"); + default: NEXT(); + } + } +} + +SQInteger SQLexer::Lex() +{ + _lasttokenline = _currentline; + while(CUR_CHAR != SQUIRREL_EOB) { + switch(CUR_CHAR){ + case '\t': case '\r': case ' ': NEXT(); continue; + case '\n': + _currentline++; + _prevtoken=_curtoken; + _curtoken='\n'; + NEXT(); + _currentcolumn=1; + continue; + case '/': + NEXT(); + switch(CUR_CHAR){ + case '*': + NEXT(); + LexBlockComment(); + continue; + case '/': + do { NEXT(); } while (CUR_CHAR != '\n' && (!IS_EOB())); + continue; + case '=': + NEXT(); + RETURN_TOKEN(TK_DIVEQ); + case '>': + NEXT(); + RETURN_TOKEN(TK_ATTR_CLOSE); + default: + RETURN_TOKEN('/'); + } + case '=': + NEXT(); + if (CUR_CHAR != '='){ RETURN_TOKEN('=') } + else { NEXT(); RETURN_TOKEN(TK_EQ); } + case '<': + NEXT(); + if ( CUR_CHAR == '=' ) { NEXT(); RETURN_TOKEN(TK_LE) } + else if ( CUR_CHAR == '-' ) { NEXT(); RETURN_TOKEN(TK_NEWSLOT); } + else if ( CUR_CHAR == '<' ) { NEXT(); RETURN_TOKEN(TK_SHIFTL); } + else if ( CUR_CHAR == '/' ) { NEXT(); RETURN_TOKEN(TK_ATTR_OPEN); } + //else if ( CUR_CHAR == '[' ) { NEXT(); ReadMultilineString(); RETURN_TOKEN(TK_STRING_LITERAL); } + else { RETURN_TOKEN('<') } + case '>': + NEXT(); + if (CUR_CHAR == '='){ NEXT(); RETURN_TOKEN(TK_GE);} + else if(CUR_CHAR == '>'){ + NEXT(); + if(CUR_CHAR == '>'){ + NEXT(); + RETURN_TOKEN(TK_USHIFTR); + } + RETURN_TOKEN(TK_SHIFTR); + } + else { RETURN_TOKEN('>') } + case '!': + NEXT(); + if (CUR_CHAR != '='){ RETURN_TOKEN('!')} + else { NEXT(); RETURN_TOKEN(TK_NE); } + case '@': { + SQInteger stype; + NEXT(); + if(CUR_CHAR != '"') + Error("string expected"); + if((stype=ReadString('"',true))!=-1) { + RETURN_TOKEN(stype); + } + Error("error parsing the string"); + } + case '"': + case '\'': { + SQInteger stype; + if((stype=ReadString(CUR_CHAR,false))!=-1){ + RETURN_TOKEN(stype); + } + Error("error parsing the string"); + } + case '{': case '}': case '(': case ')': case '[': case ']': + case ';': case ',': case '?': case '^': case '~': + {SQInteger ret = CUR_CHAR; + NEXT(); RETURN_TOKEN(ret); } + case '.': + NEXT(); + if (CUR_CHAR != '.'){ RETURN_TOKEN('.') } + NEXT(); + if (CUR_CHAR != '.'){ Error("invalid token '..'"); } + NEXT(); + RETURN_TOKEN(TK_VARPARAMS); + case '&': + NEXT(); + if (CUR_CHAR != '&'){ RETURN_TOKEN('&') } + else { NEXT(); RETURN_TOKEN(TK_AND); } + case '|': + NEXT(); + if (CUR_CHAR != '|'){ RETURN_TOKEN('|') } + else { NEXT(); RETURN_TOKEN(TK_OR); } + case ':': + NEXT(); + if (CUR_CHAR != ':'){ RETURN_TOKEN(':') } + else { NEXT(); RETURN_TOKEN(TK_DOUBLE_COLON); } + case '*': + NEXT(); + if (CUR_CHAR == '='){ NEXT(); RETURN_TOKEN(TK_MULEQ);} + else RETURN_TOKEN('*'); + case '%': + NEXT(); + if (CUR_CHAR == '='){ NEXT(); RETURN_TOKEN(TK_MODEQ);} + else RETURN_TOKEN('%'); + case '-': + NEXT(); + if (CUR_CHAR == '='){ NEXT(); RETURN_TOKEN(TK_MINUSEQ);} + else if (CUR_CHAR == '-'){ NEXT(); RETURN_TOKEN(TK_MINUSMINUS);} + else RETURN_TOKEN('-'); + case '+': + NEXT(); + if (CUR_CHAR == '='){ NEXT(); RETURN_TOKEN(TK_PLUSEQ);} + else if (CUR_CHAR == '+'){ NEXT(); RETURN_TOKEN(TK_PLUSPLUS);} + else RETURN_TOKEN('+'); + case SQUIRREL_EOB: + return 0; + default:{ + if (isdigit(CUR_CHAR)) { + SQInteger ret = ReadNumber(); + RETURN_TOKEN(ret); + } + else if (isalpha(CUR_CHAR) || CUR_CHAR == '_') { + SQInteger t = ReadID(); + RETURN_TOKEN(t); + } + else { + SQInteger c = CUR_CHAR; + if (iscntrl((int)c)) Error("unexpected character(control)"); + NEXT(); + RETURN_TOKEN(c); + } + RETURN_TOKEN(0); + } + } + } + return 0; +} + +SQInteger SQLexer::GetIDType(SQChar *s) +{ + SQObjectPtr t; + if(_keywords->Get(SQString::Create(_sharedstate, s), t)) { + return SQInteger(_integer(t)); + } + return TK_IDENTIFIER; +} + + +SQInteger SQLexer::ReadString(WChar ndelim,bool verbatim) +{ + INIT_TEMP_STRING(); + NEXT(); + if(IS_EOB()) return -1; + for(;;) { + while(CUR_CHAR != ndelim) { + switch(CUR_CHAR) { + case SQUIRREL_EOB: + Error("unfinished string"); + return -1; + case '\n': + if(!verbatim) Error("newline in a constant"); + APPEND_CHAR(CUR_CHAR); NEXT(); + _currentline++; + break; + case '\\': + if(verbatim) { + APPEND_CHAR('\\'); NEXT(); + } + else { + NEXT(); + switch(CUR_CHAR) { + case 'x': NEXT(); { + if(!isxdigit(CUR_CHAR)) Error("hexadecimal number expected"); + const SQInteger maxdigits = 4; + SQChar temp[maxdigits+1]; + SQInteger n = 0; + while(isxdigit(CUR_CHAR) && n < maxdigits) { + temp[n] = CUR_CHAR; + n++; + NEXT(); + } + temp[n] = 0; + SQChar *sTemp; + APPEND_CHAR((SQChar)strtoul(temp,&sTemp,16)); + } + break; + case 't': APPEND_CHAR('\t'); NEXT(); break; + case 'a': APPEND_CHAR('\a'); NEXT(); break; + case 'b': APPEND_CHAR('\b'); NEXT(); break; + case 'n': APPEND_CHAR('\n'); NEXT(); break; + case 'r': APPEND_CHAR('\r'); NEXT(); break; + case 'v': APPEND_CHAR('\v'); NEXT(); break; + case 'f': APPEND_CHAR('\f'); NEXT(); break; + case '0': APPEND_CHAR('\0'); NEXT(); break; + case '\\': APPEND_CHAR('\\'); NEXT(); break; + case '"': APPEND_CHAR('"'); NEXT(); break; + case '\'': APPEND_CHAR('\''); NEXT(); break; + default: + Error("unrecognised escaper char"); + break; + } + } + break; + default: + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + } + NEXT(); + if(verbatim && CUR_CHAR == '"') { //double quotation + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + else { + break; + } + } + TERMINATE_BUFFER(); + SQInteger len = _longstr.size()-1; + if(ndelim == '\'') { + if(len == 0) Error("empty constant"); + if(len > 1) Error("constant too long"); + _nvalue = _longstr[0]; + return TK_INTEGER; + } + _svalue = &_longstr[0]; + return TK_STRING_LITERAL; +} + +void LexHexadecimal(const SQChar *s,SQUnsignedInteger *res) +{ + *res = 0; + while(*s != 0) + { + if(isdigit(*s)) *res = (*res)*16+((*s++)-'0'); + else if(isxdigit(*s)) *res = (*res)*16+(toupper(*s++)-'A'+10); + else { assert(0); } + } +} + +void LexInteger(const SQChar *s,SQUnsignedInteger *res) +{ + *res = 0; + while(*s != 0) + { + *res = (*res)*10+((*s++)-'0'); + } +} + +SQInteger scisodigit(SQChar c) { return c >= '0' && c <= '7'; } + +void LexOctal(const SQChar *s,SQUnsignedInteger *res) +{ + *res = 0; + while(*s != 0) + { + if(scisodigit(*s)) *res = (*res)*8+((*s++)-'0'); + else { assert(0); } + } +} + +SQInteger isexponent(SQInteger c) { return c == 'e' || c=='E'; } + + +#define MAX_HEX_DIGITS (sizeof(SQInteger)*2) +SQInteger SQLexer::ReadNumber() +{ +#define TINT 1 +#define TFLOAT 2 +#define THEX 3 +#define TSCIENTIFIC 4 +#define TOCTAL 5 + SQInteger type = TINT, firstchar = CUR_CHAR; + SQChar *sTemp; + INIT_TEMP_STRING(); + NEXT(); + if(firstchar == '0' && (toupper(CUR_CHAR) == 'X' || scisodigit(CUR_CHAR)) ) { + if(scisodigit(CUR_CHAR)) { + type = TOCTAL; + while(scisodigit(CUR_CHAR)) { + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + if(isdigit(CUR_CHAR)) Error("invalid octal number"); + } + else { + NEXT(); + type = THEX; + while(isxdigit(CUR_CHAR)) { + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + if(_longstr.size() > MAX_HEX_DIGITS) Error("too many digits for an Hex number"); + } + } + else { + APPEND_CHAR((int)firstchar); + while (CUR_CHAR == '.' || isdigit(CUR_CHAR) || isexponent(CUR_CHAR)) { + if(CUR_CHAR == '.' || isexponent(CUR_CHAR)) type = TFLOAT; + if(isexponent(CUR_CHAR)) { + if(type != TFLOAT) Error("invalid numeric format"); + type = TSCIENTIFIC; + APPEND_CHAR(CUR_CHAR); + NEXT(); + if(CUR_CHAR == '+' || CUR_CHAR == '-'){ + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + if(!isdigit(CUR_CHAR)) Error("exponent expected"); + } + + APPEND_CHAR(CUR_CHAR); + NEXT(); + } + } + TERMINATE_BUFFER(); + switch(type) { + case TSCIENTIFIC: + case TFLOAT: + _fvalue = (SQFloat)strtod(&_longstr[0],&sTemp); + return TK_FLOAT; + case TINT: + LexInteger(&_longstr[0],(SQUnsignedInteger *)&_nvalue); + return TK_INTEGER; + case THEX: + LexHexadecimal(&_longstr[0],(SQUnsignedInteger *)&_nvalue); + return TK_INTEGER; + case TOCTAL: + LexOctal(&_longstr[0],(SQUnsignedInteger *)&_nvalue); + return TK_INTEGER; + } + return 0; +} + +SQInteger SQLexer::ReadID() +{ + SQInteger res; + INIT_TEMP_STRING(); + do { + APPEND_CHAR(CUR_CHAR); + NEXT(); + } while(isalnum(CUR_CHAR) || CUR_CHAR == '_'); + TERMINATE_BUFFER(); + res = GetIDType(&_longstr[0]); + if(res == TK_IDENTIFIER || res == TK_CONSTRUCTOR) { + _svalue = &_longstr[0]; + } + return res; +} diff --git a/src/3rdparty/squirrel/squirrel/sqlexer.h b/src/3rdparty/squirrel/squirrel/sqlexer.h new file mode 100644 index 0000000..b53b309 --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqlexer.h @@ -0,0 +1,42 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQLEXER_H_ +#define _SQLEXER_H_ + +struct SQLexer +{ + ~SQLexer(); + SQLexer(SQSharedState *ss,SQLEXREADFUNC rg,SQUserPointer up,CompilerErrorFunc efunc,void *ed); + NORETURN void Error(const SQChar *err); + SQInteger Lex(); + const SQChar *Tok2Str(SQInteger tok); +private: + SQInteger GetIDType(SQChar *s); + SQInteger ReadString(WChar ndelim,bool verbatim); + SQInteger ReadNumber(); + void LexBlockComment(); + SQInteger ReadID(); + void Next(); + SQInteger _curtoken; + SQTable *_keywords; + void INIT_TEMP_STRING() { _longstr.resize(0); } + void APPEND_CHAR(WChar c); + void TERMINATE_BUFFER() { _longstr.push_back('\0'); } + +public: + SQInteger _prevtoken; + SQInteger _currentline; + SQInteger _lasttokenline; + SQInteger _currentcolumn; + const SQChar *_svalue; + SQInteger _nvalue; + SQFloat _fvalue; + SQLEXREADFUNC _readf; + SQUserPointer _up; + WChar _currdata; + SQSharedState *_sharedstate; + sqvector _longstr; + CompilerErrorFunc _errfunc; + void *_errtarget; +}; + +#endif diff --git a/src/3rdparty/squirrel/squirrel/sqmem.cpp b/src/3rdparty/squirrel/squirrel/sqmem.cpp new file mode 100644 index 0000000..5c1b396 --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqmem.cpp @@ -0,0 +1,16 @@ +/* + * see copyright notice in squirrel.h + */ + +#include "../../../stdafx.h" + +#include "sqpcheader.h" + +#include "../../../core/alloc_func.hpp" +#include "../../../safeguards.h" + +void *sq_vm_malloc(SQUnsignedInteger size){ return MallocT((size_t)size); } + +void *sq_vm_realloc(void *p, SQUnsignedInteger oldsize, SQUnsignedInteger size){ return ReallocT(static_cast(p), (size_t)size); } + +void sq_vm_free(void *p, SQUnsignedInteger size){ free(p); } diff --git a/src/3rdparty/squirrel/squirrel/sqobject.cpp b/src/3rdparty/squirrel/squirrel/sqobject.cpp new file mode 100644 index 0000000..d48baca --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqobject.cpp @@ -0,0 +1,592 @@ +/* + * see copyright notice in squirrel.h + */ + +#include "../../../stdafx.h" + +#include "sqpcheader.h" +#include "sqvm.h" +#include "sqstring.h" +#include "sqarray.h" +#include "sqtable.h" +#include "squserdata.h" +#include "sqfuncproto.h" +#include "sqclass.h" +#include "sqclosure.h" + +#include "../../../safeguards.h" + + +const SQChar *IdType2Name(SQObjectType type) +{ + switch(_RAW_TYPE(type)) + { + case _RT_NULL:return "null"; + case _RT_INTEGER:return "integer"; + case _RT_FLOAT:return "float"; + case _RT_BOOL:return "bool"; + case _RT_STRING:return "string"; + case _RT_TABLE:return "table"; + case _RT_ARRAY:return "array"; + case _RT_GENERATOR:return "generator"; + case _RT_CLOSURE: + case _RT_NATIVECLOSURE: + return "function"; + case _RT_USERDATA: + case _RT_USERPOINTER: + return "userdata"; + case _RT_THREAD: return "thread"; + case _RT_FUNCPROTO: return "function"; + case _RT_CLASS: return "class"; + case _RT_INSTANCE: return "instance"; + case _RT_WEAKREF: return "weakref"; + default: + return NULL; + } +} + +const SQChar *GetTypeName(const SQObjectPtr &obj1) +{ + return IdType2Name(type(obj1)); +} + +SQString *SQString::Create(SQSharedState *ss,const SQChar *s,SQInteger len) +{ + SQString *str=ADD_STRING(ss,s,len); + str->_sharedstate=ss; + return str; +} + +void SQString::Release() +{ + REMOVE_STRING(_sharedstate,this); +} + +SQInteger SQString::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval) +{ + SQInteger idx = (SQInteger)TranslateIndex(refpos); + while(idx < _len){ + outkey = (SQInteger)idx; + outval = SQInteger(_val[idx]); + //return idx for the next iteration + return ++idx; + } + //nothing to iterate anymore + return -1; +} + +SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx) +{ + switch(type(idx)){ + case OT_NULL: + return 0; + case OT_INTEGER: + return (SQUnsignedInteger)_integer(idx); + default: assert(0); break; + } + return 0; +} + +SQWeakRef *SQRefCounted::GetWeakRef(SQObjectType type) +{ + if(!_weakref) { + sq_new(_weakref,SQWeakRef); + _weakref->_obj._type = type; + _weakref->_obj._unVal.pRefCounted = this; + } + return _weakref; +} + +SQRefCounted::~SQRefCounted() +{ + if(_weakref) { + _weakref->_obj._type = OT_NULL; + _weakref->_obj._unVal.pRefCounted = NULL; + } +} + +void SQWeakRef::Release() { + if(ISREFCOUNTED(_obj._type)) { + _obj._unVal.pRefCounted->_weakref = NULL; + } + sq_delete(this,SQWeakRef); +} + +bool SQDelegable::GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res) { + if(_delegate) { + return _delegate->Get((*_ss(v)->_metamethods)[mm],res); + } + return false; +} + +bool SQDelegable::SetDelegate(SQTable *mt) +{ + SQTable *temp = mt; + if(temp == this) return false; + while (temp) { + if (temp->_delegate == this) return false; //cycle detected + temp = temp->_delegate; + } + if (mt) __ObjAddRef(mt); + __ObjRelease(_delegate); + _delegate = mt; + return true; +} + +bool SQGenerator::Yield(SQVM *v) +{ + if(_state==eSuspended) { v->Raise_Error("internal vm error, yielding dead generator"); return false;} + if(_state==eDead) { v->Raise_Error("internal vm error, yielding a dead generator"); return false; } + SQInteger size = v->_top-v->_stackbase; + _ci=*v->ci; + _stack.resize(size); + for(SQInteger n =0; n_stack[v->_stackbase+n]; + v->_stack[v->_stackbase+n] = _null_; + } + SQInteger nvargs = v->ci->_vargs.size; + SQInteger vargsbase = v->ci->_vargs.base; + for(SQInteger j = nvargs - 1; j >= 0; j--) { + _vargsstack.push_back(v->_vargsstack[vargsbase+j]); + } + _ci._generator=NULL; + for(SQInteger i=0;i<_ci._etraps;i++) { + _etraps.push_back(v->_etraps.top()); + v->_etraps.pop_back(); + } + _state=eSuspended; + return true; +} + +bool SQGenerator::Resume(SQVM *v,SQInteger target) +{ + SQInteger size=_stack.size(); + if(_state==eDead){ v->Raise_Error("resuming dead generator"); return false; } + if(_state==eRunning){ v->Raise_Error("resuming active generator"); return false; } + SQInteger prevtop=v->_top-v->_stackbase; + PUSH_CALLINFO(v,_ci); + SQInteger oldstackbase=v->_stackbase; + v->_stackbase = v->_top; + v->ci->_target = (SQInt32)target; + v->ci->_generator = this; + v->ci->_vargs.size = (unsigned short)_vargsstack.size(); + + for(SQInteger i=0;i<_ci._etraps;i++) { + v->_etraps.push_back(_etraps.top()); + _etraps.pop_back(); + } + for(SQInteger n =0; n_stack[v->_stackbase+n] = _stack._vals[n]; + _stack._vals[0] = _null_; + } + while(_vargsstack.size()) { + v->_vargsstack.push_back(_vargsstack.back()); + _vargsstack.pop_back(); + } + v->ci->_vargs.base = (unsigned short)(v->_vargsstack.size() - v->ci->_vargs.size); + v->_top=v->_stackbase+size; + v->ci->_prevtop = (SQInt32)prevtop; + v->ci->_prevstkbase = (SQInt32)(v->_stackbase - oldstackbase); + _state=eRunning; + if (type(v->_debughook) != OT_NULL && _rawval(v->_debughook) != _rawval(v->ci->_closure)) + v->CallDebugHook('c'); + + return true; +} + +void SQArray::Extend(const SQArray *a){ + SQInteger xlen; + if((xlen=a->Size())) + for(SQInteger i=0;i_values[i]); +} + +const SQChar* SQFunctionProto::GetLocal(SQVM *vm,SQUnsignedInteger stackbase,SQUnsignedInteger nseq,SQUnsignedInteger nop) +{ + SQUnsignedInteger nvars=_nlocalvarinfos; + const SQChar *res=NULL; + if(nvars>=nseq){ + for(SQUnsignedInteger i=0;i=nop) + { + if(nseq==0){ + vm->Push(vm->_stack[stackbase+_localvarinfos[i]._pos]); + res=_stringval(_localvarinfos[i]._name); + break; + } + nseq--; + } + } + } + return res; +} + +SQInteger SQFunctionProto::GetLine(SQInstruction *curr) +{ + SQInteger op = (SQInteger)(curr-_instructions); + SQInteger line=_lineinfos[0]._line; + for(SQInteger i=1;i<_nlineinfos;i++){ + if(_lineinfos[i]._op>=op) + return line; + line=_lineinfos[i]._line; + } + return line; +} + +#define _CHECK_IO(exp) { if(!exp)return false; } +bool SafeWrite(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,SQUserPointer dest,SQInteger size) +{ + if(write(up,dest,size) != size) { + v->Raise_Error("io error (write function failure)"); + return false; + } + return true; +} + +bool SafeRead(HSQUIRRELVM v,SQWRITEFUNC read,SQUserPointer up,SQUserPointer dest,SQInteger size) +{ + if(size && read(up,dest,size) != size) { + v->Raise_Error("io error, read function failure, the origin stream could be corrupted/trucated"); + return false; + } + return true; +} + +bool WriteTag(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,SQInteger tag) +{ + return SafeWrite(v,write,up,&tag,sizeof(tag)); +} + +bool CheckTag(HSQUIRRELVM v,SQWRITEFUNC read,SQUserPointer up,SQInteger tag) +{ + SQInteger t; + _CHECK_IO(SafeRead(v,read,up,&t,sizeof(t))); + if(t != tag){ + v->Raise_Error("invalid or corrupted closure stream"); + return false; + } + return true; +} + +bool WriteObject(HSQUIRRELVM v,SQUserPointer up,SQWRITEFUNC write,SQObjectPtr &o) +{ + _CHECK_IO(SafeWrite(v,write,up,&type(o),sizeof(SQObjectType))); + switch(type(o)){ + case OT_STRING: + _CHECK_IO(SafeWrite(v,write,up,&_string(o)->_len,sizeof(SQInteger))); + _CHECK_IO(SafeWrite(v,write,up,_stringval(o),_string(o)->_len)); + break; + case OT_INTEGER: + _CHECK_IO(SafeWrite(v,write,up,&_integer(o),sizeof(SQInteger)));break; + case OT_FLOAT: + _CHECK_IO(SafeWrite(v,write,up,&_float(o),sizeof(SQFloat)));break; + case OT_NULL: + break; + default: + v->Raise_Error("cannot serialize a %s",GetTypeName(o)); + return false; + } + return true; +} + +bool ReadObject(HSQUIRRELVM v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &o) +{ + SQObjectType t; + _CHECK_IO(SafeRead(v,read,up,&t,sizeof(SQObjectType))); + switch(t){ + case OT_STRING:{ + SQInteger len; + _CHECK_IO(SafeRead(v,read,up,&len,sizeof(SQInteger))); + _CHECK_IO(SafeRead(v,read,up,_ss(v)->GetScratchPad(len),len)); + o=SQString::Create(_ss(v),_ss(v)->GetScratchPad(-1),len); + } + break; + case OT_INTEGER:{ + SQInteger i; + _CHECK_IO(SafeRead(v,read,up,&i,sizeof(SQInteger))); o = i; break; + } + case OT_FLOAT:{ + SQFloat f; + _CHECK_IO(SafeRead(v,read,up,&f,sizeof(SQFloat))); o = f; break; + } + case OT_NULL: + o=_null_; + break; + default: + v->Raise_Error("cannot serialize a %s",IdType2Name(t)); + return false; + } + return true; +} + +bool SQClosure::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write) +{ + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_HEAD)); + _CHECK_IO(WriteTag(v,write,up,sizeof(SQChar))); + _CHECK_IO(_funcproto(_function)->Save(v,up,write)); + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_TAIL)); + return true; +} + +bool SQClosure::Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret) +{ + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_HEAD)); + _CHECK_IO(CheckTag(v,read,up,sizeof(SQChar))); + SQObjectPtr func; + _CHECK_IO(SQFunctionProto::Load(v,up,read,func)); + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_TAIL)); + ret = SQClosure::Create(_ss(v),_funcproto(func)); + return true; +} + +bool SQFunctionProto::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write) +{ + SQInteger i,nliterals = _nliterals,nparameters = _nparameters; + SQInteger noutervalues = _noutervalues,nlocalvarinfos = _nlocalvarinfos; + SQInteger nlineinfos=_nlineinfos,ninstructions = _ninstructions,nfunctions=_nfunctions; + SQInteger ndefaultparams = _ndefaultparams; + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(WriteObject(v,up,write,_sourcename)); + _CHECK_IO(WriteObject(v,up,write,_name)); + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeWrite(v,write,up,&nliterals,sizeof(nliterals))); + _CHECK_IO(SafeWrite(v,write,up,&nparameters,sizeof(nparameters))); + _CHECK_IO(SafeWrite(v,write,up,&noutervalues,sizeof(noutervalues))); + _CHECK_IO(SafeWrite(v,write,up,&nlocalvarinfos,sizeof(nlocalvarinfos))); + _CHECK_IO(SafeWrite(v,write,up,&nlineinfos,sizeof(nlineinfos))); + _CHECK_IO(SafeWrite(v,write,up,&ndefaultparams,sizeof(ndefaultparams))); + _CHECK_IO(SafeWrite(v,write,up,&ninstructions,sizeof(ninstructions))); + _CHECK_IO(SafeWrite(v,write,up,&nfunctions,sizeof(nfunctions))); + _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); + for(i=0;iSave(v,up,write)); + } + _CHECK_IO(SafeWrite(v,write,up,&_stacksize,sizeof(_stacksize))); + _CHECK_IO(SafeWrite(v,write,up,&_bgenerator,sizeof(_bgenerator))); + _CHECK_IO(SafeWrite(v,write,up,&_varparams,sizeof(_varparams))); + return true; +} + +bool SQFunctionProto::Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret) +{ + SQInteger i, nliterals,nparameters; + SQInteger noutervalues ,nlocalvarinfos ; + SQInteger nlineinfos,ninstructions ,nfunctions,ndefaultparams ; + SQObjectPtr sourcename, name; + SQObjectPtr o; + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(ReadObject(v, up, read, sourcename)); + _CHECK_IO(ReadObject(v, up, read, name)); + + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up, &nliterals, sizeof(nliterals))); + _CHECK_IO(SafeRead(v,read,up, &nparameters, sizeof(nparameters))); + _CHECK_IO(SafeRead(v,read,up, &noutervalues, sizeof(noutervalues))); + _CHECK_IO(SafeRead(v,read,up, &nlocalvarinfos, sizeof(nlocalvarinfos))); + _CHECK_IO(SafeRead(v,read,up, &nlineinfos, sizeof(nlineinfos))); + _CHECK_IO(SafeRead(v,read,up, &ndefaultparams, sizeof(ndefaultparams))); + _CHECK_IO(SafeRead(v,read,up, &ninstructions, sizeof(ninstructions))); + _CHECK_IO(SafeRead(v,read,up, &nfunctions, sizeof(nfunctions))); + + + SQFunctionProto *f = SQFunctionProto::Create(ninstructions,nliterals,nparameters, + nfunctions,noutervalues,nlineinfos,nlocalvarinfos,ndefaultparams); + SQObjectPtr proto = f; //gets a ref in case of failure + f->_sourcename = sourcename; + f->_name = name; + + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + + for(i = 0;i < nliterals; i++){ + _CHECK_IO(ReadObject(v, up, read, o)); + f->_literals[i] = o; + } + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + + for(i = 0; i < nparameters; i++){ + _CHECK_IO(ReadObject(v, up, read, o)); + f->_parameters[i] = o; + } + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + + for(i = 0; i < noutervalues; i++){ + SQUnsignedInteger type; + SQObjectPtr name; + _CHECK_IO(SafeRead(v,read,up, &type, sizeof(SQUnsignedInteger))); + _CHECK_IO(ReadObject(v, up, read, o)); + _CHECK_IO(ReadObject(v, up, read, name)); + f->_outervalues[i] = SQOuterVar(name,o, (SQOuterType)type); + } + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + + for(i = 0; i < nlocalvarinfos; i++){ + SQLocalVarInfo lvi; + _CHECK_IO(ReadObject(v, up, read, lvi._name)); + _CHECK_IO(SafeRead(v,read,up, &lvi._pos, sizeof(SQUnsignedInteger))); + _CHECK_IO(SafeRead(v,read,up, &lvi._start_op, sizeof(SQUnsignedInteger))); + _CHECK_IO(SafeRead(v,read,up, &lvi._end_op, sizeof(SQUnsignedInteger))); + f->_localvarinfos[i] = lvi; + } + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up, f->_lineinfos, sizeof(SQLineInfo)*nlineinfos)); + + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up, f->_defaultparams, sizeof(SQInteger)*ndefaultparams)); + + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + _CHECK_IO(SafeRead(v,read,up, f->_instructions, sizeof(SQInstruction)*ninstructions)); + + _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); + for(i = 0; i < nfunctions; i++){ + _CHECK_IO(_funcproto(o)->Load(v, up, read, o)); + f->_functions[i] = o; + } + _CHECK_IO(SafeRead(v,read,up, &f->_stacksize, sizeof(f->_stacksize))); + _CHECK_IO(SafeRead(v,read,up, &f->_bgenerator, sizeof(f->_bgenerator))); + _CHECK_IO(SafeRead(v,read,up, &f->_varparams, sizeof(f->_varparams))); + + ret = f; + return true; +} + +#ifndef NO_GARBAGE_COLLECTOR + +#define START_MARK() if(!(_uiRef&MARK_FLAG)){ \ + _uiRef|=MARK_FLAG; + +#define END_MARK() RemoveFromChain(&_sharedstate->_gc_chain, this); \ + AddToChain(chain, this); } + +void SQVM::Mark(SQCollectable **chain) +{ + START_MARK() + SQSharedState::MarkObject(_lasterror,chain); + SQSharedState::MarkObject(_errorhandler,chain); + SQSharedState::MarkObject(_debughook,chain); + SQSharedState::MarkObject(_roottable, chain); + SQSharedState::MarkObject(temp_reg, chain); + for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain); + for(SQUnsignedInteger j = 0; j < _vargsstack.size(); j++) SQSharedState::MarkObject(_vargsstack[j], chain); + for(SQInteger k = 0; k < _callsstacksize; k++) SQSharedState::MarkObject(_callsstack[k]._closure, chain); + END_MARK() +} + +void SQArray::Mark(SQCollectable **chain) +{ + START_MARK() + SQInteger len = _values.size(); + for(SQInteger i = 0;i < len; i++) SQSharedState::MarkObject(_values[i], chain); + END_MARK() +} +void SQTable::Mark(SQCollectable **chain) +{ + START_MARK() + if(_delegate) _delegate->Mark(chain); + SQInteger len = _numofnodes; + for(SQInteger i = 0; i < len; i++){ + SQSharedState::MarkObject(_nodes[i].key, chain); + SQSharedState::MarkObject(_nodes[i].val, chain); + } + END_MARK() +} + +void SQClass::Mark(SQCollectable **chain) +{ + START_MARK() + _members->Mark(chain); + if(_base) _base->Mark(chain); + SQSharedState::MarkObject(_attributes, chain); + for(SQUnsignedInteger i =0; i< _defaultvalues.size(); i++) { + SQSharedState::MarkObject(_defaultvalues[i].val, chain); + SQSharedState::MarkObject(_defaultvalues[i].attrs, chain); + } + for(SQUnsignedInteger j =0; j< _methods.size(); j++) { + SQSharedState::MarkObject(_methods[j].val, chain); + SQSharedState::MarkObject(_methods[j].attrs, chain); + } + for(SQUnsignedInteger k =0; k< _metamethods.size(); k++) { + SQSharedState::MarkObject(_metamethods[k], chain); + } + END_MARK() +} + +void SQInstance::Mark(SQCollectable **chain) +{ + START_MARK() + _class->Mark(chain); + SQUnsignedInteger nvalues = _class->_defaultvalues.size(); + for(SQUnsignedInteger i =0; i< nvalues; i++) { + SQSharedState::MarkObject(_values[i], chain); + } + END_MARK() +} + +void SQGenerator::Mark(SQCollectable **chain) +{ + START_MARK() + for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain); + for(SQUnsignedInteger j = 0; j < _vargsstack.size(); j++) SQSharedState::MarkObject(_vargsstack[j], chain); + SQSharedState::MarkObject(_closure, chain); + END_MARK() +} + +void SQClosure::Mark(SQCollectable **chain) +{ + START_MARK() + for(SQUnsignedInteger i = 0; i < _outervalues.size(); i++) SQSharedState::MarkObject(_outervalues[i], chain); + for(SQUnsignedInteger i = 0; i < _defaultparams.size(); i++) SQSharedState::MarkObject(_defaultparams[i], chain); + END_MARK() +} + +void SQNativeClosure::Mark(SQCollectable **chain) +{ + START_MARK() + for(SQUnsignedInteger i = 0; i < _outervalues.size(); i++) SQSharedState::MarkObject(_outervalues[i], chain); + END_MARK() +} + +void SQUserData::Mark(SQCollectable **chain){ + START_MARK() + if(_delegate) _delegate->Mark(chain); + END_MARK() +} + +void SQCollectable::UnMark() { _uiRef&=~MARK_FLAG; } + +#endif + diff --git a/src/3rdparty/squirrel/squirrel/sqobject.h b/src/3rdparty/squirrel/squirrel/sqobject.h new file mode 100644 index 0000000..d71e515 --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqobject.h @@ -0,0 +1,381 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQOBJECT_H_ +#define _SQOBJECT_H_ + +#include "squtils.h" + +#define SQ_CLOSURESTREAM_HEAD (('S'<<24)|('Q'<<16)|('I'<<8)|('R')) +#define SQ_CLOSURESTREAM_PART (('P'<<24)|('A'<<16)|('R'<<8)|('T')) +#define SQ_CLOSURESTREAM_TAIL (('T'<<24)|('A'<<16)|('I'<<8)|('L')) + +struct SQSharedState; + +enum SQMetaMethod{ + MT_ADD=0, + MT_SUB=1, + MT_MUL=2, + MT_DIV=3, + MT_UNM=4, + MT_MODULO=5, + MT_SET=6, + MT_GET=7, + MT_TYPEOF=8, + MT_NEXTI=9, + MT_CMP=10, + MT_CALL=11, + MT_CLONED=12, + MT_NEWSLOT=13, + MT_DELSLOT=14, + MT_TOSTRING=15, + MT_NEWMEMBER=16, + MT_INHERITED=17, + MT_LAST = 18 +}; + +#define MM_ADD "_add" +#define MM_SUB "_sub" +#define MM_MUL "_mul" +#define MM_DIV "_div" +#define MM_UNM "_unm" +#define MM_MODULO "_modulo" +#define MM_SET "_set" +#define MM_GET "_get" +#define MM_TYPEOF "_typeof" +#define MM_NEXTI "_nexti" +#define MM_CMP "_cmp" +#define MM_CALL "_call" +#define MM_CLONED "_cloned" +#define MM_NEWSLOT "_newslot" +#define MM_DELSLOT "_delslot" +#define MM_TOSTRING "_tostring" +#define MM_NEWMEMBER "_newmember" +#define MM_INHERITED "_inherited" + +#define MINPOWER2 4 + +struct SQRefCounted +{ + SQRefCounted() { _uiRef = 0; _weakref = NULL; } + virtual ~SQRefCounted(); + SQWeakRef *GetWeakRef(SQObjectType type); + SQUnsignedInteger _uiRef; + struct SQWeakRef *_weakref; + virtual void Release()=0; +}; + +struct SQWeakRef : SQRefCounted +{ + void Release(); + SQObject _obj; +}; + +#define _realval(o) (type((o)) != OT_WEAKREF?(SQObject)o:_weakref(o)->_obj) + +struct SQObjectPtr; + +#define __AddRef(type,unval) if(ISREFCOUNTED(type)) \ + { \ + unval.pRefCounted->_uiRef++; \ + } + +#define __Release(type,unval) if(ISREFCOUNTED(type) && ((--unval.pRefCounted->_uiRef)<=0)) \ + { \ + unval.pRefCounted->Release(); \ + } + +#define __ObjRelease(obj) { \ + if((obj)) { \ + (obj)->_uiRef--; \ + if((obj)->_uiRef == 0) \ + (obj)->Release(); \ + (obj) = NULL; \ + } \ +} + +#define __ObjAddRef(obj) { \ + (obj)->_uiRef++; \ +} + +#define type(obj) ((obj)._type) +#define is_delegable(t) (type(t)&SQOBJECT_DELEGABLE) +#define raw_type(obj) _RAW_TYPE((obj)._type) + +#define _integer(obj) ((obj)._unVal.nInteger) +#define _float(obj) ((obj)._unVal.fFloat) +#define _string(obj) ((obj)._unVal.pString) +#define _table(obj) ((obj)._unVal.pTable) +#define _array(obj) ((obj)._unVal.pArray) +#define _closure(obj) ((obj)._unVal.pClosure) +#define _generator(obj) ((obj)._unVal.pGenerator) +#define _nativeclosure(obj) ((obj)._unVal.pNativeClosure) +#define _userdata(obj) ((obj)._unVal.pUserData) +#define _userpointer(obj) ((obj)._unVal.pUserPointer) +#define _thread(obj) ((obj)._unVal.pThread) +#define _funcproto(obj) ((obj)._unVal.pFunctionProto) +#define _class(obj) ((obj)._unVal.pClass) +#define _instance(obj) ((obj)._unVal.pInstance) +#define _delegable(obj) ((SQDelegable *)(obj)._unVal.pDelegable) +#define _weakref(obj) ((obj)._unVal.pWeakRef) +#define _refcounted(obj) ((obj)._unVal.pRefCounted) +#define _rawval(obj) ((obj)._unVal.raw) + +#define _stringval(obj) (obj)._unVal.pString->_val +#define _userdataval(obj) (obj)._unVal.pUserData->_val + +#define tofloat(num) ((type(num)==OT_INTEGER)?(SQFloat)_integer(num):_float(num)) +#define tointeger(num) ( (type(num)==OT_FLOAT)?(SQInteger)_float(num):_integer(num)) + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +struct SQObjectPtr : public SQObject +{ + SQObjectPtr() + { + SQ_OBJECT_RAWINIT() + _type=OT_NULL; + _unVal.pUserPointer=NULL; + } + SQObjectPtr(const SQObjectPtr &o) + { + SQ_OBJECT_RAWINIT() + _type=o._type; + _unVal=o._unVal; + __AddRef(_type,_unVal); + } + SQObjectPtr(const SQObject &o) + { + SQ_OBJECT_RAWINIT() + _type=o._type; + _unVal=o._unVal; + __AddRef(_type,_unVal); + } + SQObjectPtr(SQTable *pTable) + { + SQ_OBJECT_RAWINIT() + _type=OT_TABLE; + _unVal.pTable=pTable; + assert(_unVal.pTable); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQClass *pClass) + { + SQ_OBJECT_RAWINIT() + _type=OT_CLASS; + _unVal.pClass=pClass; + assert(_unVal.pClass); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQInstance *pInstance) + { + SQ_OBJECT_RAWINIT() + _type=OT_INSTANCE; + _unVal.pInstance=pInstance; + assert(_unVal.pInstance); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQArray *pArray) + { + SQ_OBJECT_RAWINIT() + _type=OT_ARRAY; + _unVal.pArray=pArray; + assert(_unVal.pArray); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQClosure *pClosure) + { + SQ_OBJECT_RAWINIT() + _type=OT_CLOSURE; + _unVal.pClosure=pClosure; + assert(_unVal.pClosure); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQGenerator *pGenerator) + { + SQ_OBJECT_RAWINIT() + _type=OT_GENERATOR; + _unVal.pGenerator=pGenerator; + assert(_unVal.pGenerator); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQNativeClosure *pNativeClosure) + { + SQ_OBJECT_RAWINIT() + _type=OT_NATIVECLOSURE; + _unVal.pNativeClosure=pNativeClosure; + assert(_unVal.pNativeClosure); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQString *pString) + { + SQ_OBJECT_RAWINIT() + _type=OT_STRING; + _unVal.pString=pString; + assert(_unVal.pString); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQUserData *pUserData) + { + SQ_OBJECT_RAWINIT() + _type=OT_USERDATA; + _unVal.pUserData=pUserData; + assert(_unVal.pUserData); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQVM *pThread) + { + SQ_OBJECT_RAWINIT() + _type=OT_THREAD; + _unVal.pThread=pThread; + assert(_unVal.pThread); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQWeakRef *pWeakRef) + { + SQ_OBJECT_RAWINIT() + _type=OT_WEAKREF; + _unVal.pWeakRef=pWeakRef; + assert(_unVal.pWeakRef); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQFunctionProto *pFunctionProto) + { + SQ_OBJECT_RAWINIT() + _type=OT_FUNCPROTO; + _unVal.pFunctionProto=pFunctionProto; + assert(_unVal.pFunctionProto); + __AddRef(_type,_unVal); + } + SQObjectPtr(SQInteger nInteger) + { + SQ_OBJECT_RAWINIT() + _type=OT_INTEGER; + _unVal.nInteger=nInteger; + } + SQObjectPtr(SQFloat fFloat) + { + SQ_OBJECT_RAWINIT() + _type=OT_FLOAT; + _unVal.fFloat=fFloat; + } + SQObjectPtr(bool bBool) + { + SQ_OBJECT_RAWINIT() + _type = OT_BOOL; + _unVal.nInteger = bBool?1:0; + } + SQObjectPtr(SQUserPointer pUserPointer) + { + SQ_OBJECT_RAWINIT() + _type=OT_USERPOINTER; + _unVal.pUserPointer=pUserPointer; + } + ~SQObjectPtr() + { + __Release(_type,_unVal); + } + inline void Null() + { + SQObjectType tOldType; + SQObjectValue unOldVal; + tOldType = _type; + unOldVal = _unVal; + _type = OT_NULL; + _unVal.pUserPointer = NULL; + __Release(tOldType,unOldVal); + } + inline SQObjectPtr& operator=(SQInteger i) + { + __Release(_type,_unVal); + SQ_OBJECT_RAWINIT() + _unVal.nInteger = i; + _type = OT_INTEGER; + return *this; + } + inline SQObjectPtr& operator=(SQFloat f) + { + __Release(_type,_unVal); + SQ_OBJECT_RAWINIT() + _unVal.fFloat = f; + _type = OT_FLOAT; + return *this; + } + inline SQObjectPtr& operator=(const SQObjectPtr& obj) + { + SQObjectType tOldType; + SQObjectValue unOldVal; + tOldType=_type; + unOldVal=_unVal; + _unVal = obj._unVal; + _type = obj._type; + __AddRef(_type,_unVal); + __Release(tOldType,unOldVal); + return *this; + } + inline SQObjectPtr& operator=(const SQObject& obj) + { + SQObjectType tOldType; + SQObjectValue unOldVal; + tOldType=_type; + unOldVal=_unVal; + _unVal = obj._unVal; + _type = obj._type; + __AddRef(_type,_unVal); + __Release(tOldType,unOldVal); + return *this; + } + private: + SQObjectPtr(const SQChar *){} //safety +}; + +inline void _Swap(SQObject &a,SQObject &b) +{ + SQObjectType tOldType = a._type; + SQObjectValue unOldVal = a._unVal; + a._type = b._type; + a._unVal = b._unVal; + b._type = tOldType; + b._unVal = unOldVal; +} +///////////////////////////////////////////////////////////////////////////////////// +#ifndef NO_GARBAGE_COLLECTOR +#define MARK_FLAG 0x80000000 +struct SQCollectable : public SQRefCounted { + SQCollectable *_next; + SQCollectable *_prev; + SQSharedState *_sharedstate; + virtual void Release()=0; + virtual void Mark(SQCollectable **chain)=0; + void UnMark(); + virtual void Finalize()=0; + static void AddToChain(SQCollectable **chain,SQCollectable *c); + static void RemoveFromChain(SQCollectable **chain,SQCollectable *c); +}; + + +#define ADD_TO_CHAIN(chain,obj) AddToChain(chain,obj) +#define REMOVE_FROM_CHAIN(chain,obj) {if(!(_uiRef&MARK_FLAG))RemoveFromChain(chain,obj);} +#define CHAINABLE_OBJ SQCollectable +#define INIT_CHAIN() {_next=NULL;_prev=NULL;_sharedstate=ss;} +#else + +#define ADD_TO_CHAIN(chain,obj) ((void)0) +#define REMOVE_FROM_CHAIN(chain,obj) ((void)0) +#define CHAINABLE_OBJ SQRefCounted +#define INIT_CHAIN() ((void)0) +#endif + +struct SQDelegable : public CHAINABLE_OBJ { + bool SetDelegate(SQTable *m); + virtual bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res); + SQTable *_delegate; +}; + +SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx); +typedef sqvector SQObjectPtrVec; +typedef sqvector SQIntVec; +const SQChar *GetTypeName(const SQObjectPtr &obj1); +const SQChar *IdType2Name(SQObjectType type); + + + +#endif //_SQOBJECT_H_ diff --git a/src/3rdparty/squirrel/squirrel/sqopcodes.h b/src/3rdparty/squirrel/squirrel/sqopcodes.h new file mode 100644 index 0000000..a9e4a87 --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqopcodes.h @@ -0,0 +1,115 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQOPCODES_H_ +#define _SQOPCODES_H_ + +#define MAX_FUNC_STACKSIZE 0xFF +#define MAX_LITERALS ((SQInteger)0x7FFFFFFF) + +enum BitWiseOP { + BW_AND = 0, + BW_OR = 2, + BW_XOR = 3, + BW_SHIFTL = 4, + BW_SHIFTR = 5, + BW_USHIFTR = 6 +}; + +enum CmpOP { + CMP_G = 0, + CMP_GE = 2, + CMP_L = 3, + CMP_LE = 4 +}; +enum SQOpcode +{ + _OP_LINE= 0x00, + _OP_LOAD= 0x01, + _OP_LOADINT= 0x02, + _OP_LOADFLOAT= 0x03, + _OP_DLOAD= 0x04, + _OP_TAILCALL= 0x05, + _OP_CALL= 0x06, + _OP_PREPCALL= 0x07, + _OP_PREPCALLK= 0x08, + _OP_GETK= 0x09, + _OP_MOVE= 0x0A, + _OP_NEWSLOT= 0x0B, + _OP_DELETE= 0x0C, + _OP_SET= 0x0D, + _OP_GET= 0x0E, + _OP_EQ= 0x0F, + _OP_NE= 0x10, + _OP_ARITH= 0x11, + _OP_BITW= 0x12, + _OP_RETURN= 0x13, + _OP_LOADNULLS= 0x14, + _OP_LOADROOTTABLE= 0x15, + _OP_LOADBOOL= 0x16, + _OP_DMOVE= 0x17, + _OP_JMP= 0x18, + _OP_JNZ= 0x19, + _OP_JZ= 0x1A, + _OP_LOADFREEVAR= 0x1B, + _OP_VARGC= 0x1C, + _OP_GETVARGV= 0x1D, + _OP_NEWTABLE= 0x1E, + _OP_NEWARRAY= 0x1F, + _OP_APPENDARRAY= 0x20, + _OP_GETPARENT= 0x21, + _OP_COMPARITH= 0x22, + _OP_COMPARITHL= 0x23, + _OP_INC= 0x24, + _OP_INCL= 0x25, + _OP_PINC= 0x26, + _OP_PINCL= 0x27, + _OP_CMP= 0x28, + _OP_EXISTS= 0x29, + _OP_INSTANCEOF= 0x2A, + _OP_AND= 0x2B, + _OP_OR= 0x2C, + _OP_NEG= 0x2D, + _OP_NOT= 0x2E, + _OP_BWNOT= 0x2F, + _OP_CLOSURE= 0x30, + _OP_YIELD= 0x31, + _OP_RESUME= 0x32, + _OP_FOREACH= 0x33, + _OP_POSTFOREACH= 0x34, + _OP_DELEGATE= 0x35, + _OP_CLONE= 0x36, + _OP_TYPEOF= 0x37, + _OP_PUSHTRAP= 0x38, + _OP_POPTRAP= 0x39, + _OP_THROW= 0x3A, + _OP_CLASS= 0x3B, + _OP_NEWSLOTA= 0x3C, + _OP_SCOPE_END= 0x3D, +}; + +struct SQInstructionDesc { + const SQChar *name; +}; + +struct SQInstruction +{ + SQInstruction(SQOpcode _op=_OP_SCOPE_END,SQInteger a0=0,SQInteger a1=0,SQInteger a2=0,SQInteger a3=0) + { op = _op; + _arg0 = (unsigned char)a0;_arg1 = (SQInt32)a1; + _arg2 = (unsigned char)a2;_arg3 = (unsigned char)a3; + } + + + SQInt32 _arg1; + unsigned char op; + unsigned char _arg0; + unsigned char _arg2; + unsigned char _arg3; +}; + +#include "squtils.h" +typedef sqvector SQInstructionVec; + +#define NEW_SLOT_ATTRIBUTES_FLAG 0x01 +#define NEW_SLOT_STATIC_FLAG 0x02 + +#endif // _SQOPCODES_H_ diff --git a/src/3rdparty/squirrel/squirrel/sqpcheader.h b/src/3rdparty/squirrel/squirrel/sqpcheader.h new file mode 100644 index 0000000..3cebdd1 --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqpcheader.h @@ -0,0 +1,15 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQPCHEADER_H_ +#define _SQPCHEADER_H_ + +#if defined(_MSC_VER) && defined(_DEBUG) +#include +#endif + +#include +//squirrel stuff +#include +#include "sqobject.h" +#include "sqstate.h" + +#endif //_SQPCHEADER_H_ diff --git a/src/3rdparty/squirrel/squirrel/sqstate.cpp b/src/3rdparty/squirrel/squirrel/sqstate.cpp new file mode 100644 index 0000000..35878e1 --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqstate.cpp @@ -0,0 +1,585 @@ +/* + * see copyright notice in squirrel.h + */ + +#include "../../../stdafx.h" + +#include "sqpcheader.h" +#include "sqopcodes.h" +#include "sqvm.h" +#include "sqfuncproto.h" +#include "sqclosure.h" +#include "sqstring.h" +#include "sqtable.h" +#include "sqarray.h" +#include "squserdata.h" +#include "sqclass.h" + +#include "../../../safeguards.h" + +SQObjectPtr _null_; +SQObjectPtr _true_(true); +SQObjectPtr _false_(false); +SQObjectPtr _one_((SQInteger)1); +SQObjectPtr _minusone_((SQInteger)-1); + +#define newsysstring(s) { \ + _systemstrings->push_back(SQString::Create(this,s)); \ + } + +#define newmetamethod(s) { \ + _metamethods->push_back(SQString::Create(this,s)); \ + _table(_metamethodsmap)->NewSlot(_metamethods->back(),(SQInteger)(_metamethods->size()-1)); \ + } + +bool CompileTypemask(SQIntVec &res,const SQChar *typemask) +{ + SQInteger i = 0; + + SQInteger mask = 0; + while(typemask[i] != 0) { + + switch(typemask[i]){ + case 'o': mask |= _RT_NULL; break; + case 'i': mask |= _RT_INTEGER; break; + case 'f': mask |= _RT_FLOAT; break; + case 'n': mask |= (_RT_FLOAT | _RT_INTEGER); break; + case 's': mask |= _RT_STRING; break; + case 't': mask |= _RT_TABLE; break; + case 'a': mask |= _RT_ARRAY; break; + case 'u': mask |= _RT_USERDATA; break; + case 'c': mask |= (_RT_CLOSURE | _RT_NATIVECLOSURE); break; + case 'b': mask |= _RT_BOOL; break; + case 'g': mask |= _RT_GENERATOR; break; + case 'p': mask |= _RT_USERPOINTER; break; + case 'v': mask |= _RT_THREAD; break; + case 'x': mask |= _RT_INSTANCE; break; + case 'y': mask |= _RT_CLASS; break; + case 'r': mask |= _RT_WEAKREF; break; + case '.': mask = -1; res.push_back(mask); i++; mask = 0; continue; + case ' ': i++; continue; //ignores spaces + default: + return false; + } + i++; + if(typemask[i] == '|') { + i++; + if(typemask[i] == 0) + return false; + continue; + } + res.push_back(mask); + mask = 0; + + } + return true; +} + +SQTable *CreateDefaultDelegate(SQSharedState *ss,SQRegFunction *funcz) +{ + SQInteger i=0; + SQTable *t=SQTable::Create(ss,0); + while(funcz[i].name!=0){ + SQNativeClosure *nc = SQNativeClosure::Create(ss,funcz[i].f); + nc->_nparamscheck = funcz[i].nparamscheck; + nc->_name = SQString::Create(ss,funcz[i].name); + if(funcz[i].typemask && !CompileTypemask(nc->_typecheck,funcz[i].typemask)) + return NULL; + t->NewSlot(SQString::Create(ss,funcz[i].name),nc); + i++; + } + return t; +} + +SQSharedState::SQSharedState() +{ + _compilererrorhandler = NULL; + _printfunc = NULL; + _debuginfo = false; + _notifyallexceptions = false; + _scratchpad=NULL; + _scratchpadsize=0; +#ifndef NO_GARBAGE_COLLECTOR + _gc_chain=NULL; +#endif + sq_new(_stringtable,SQStringTable); + sq_new(_metamethods,SQObjectPtrVec); + sq_new(_systemstrings,SQObjectPtrVec); + sq_new(_types,SQObjectPtrVec); + _metamethodsmap = SQTable::Create(this,MT_LAST-1); + //adding type strings to avoid memory trashing + //types names + newsysstring("null"); + newsysstring("table"); + newsysstring("array"); + newsysstring("closure"); + newsysstring("string"); + newsysstring("userdata"); + newsysstring("integer"); + newsysstring("float"); + newsysstring("userpointer"); + newsysstring("function"); + newsysstring("generator"); + newsysstring("thread"); + newsysstring("class"); + newsysstring("instance"); + newsysstring("bool"); + //meta methods + newmetamethod(MM_ADD); + newmetamethod(MM_SUB); + newmetamethod(MM_MUL); + newmetamethod(MM_DIV); + newmetamethod(MM_UNM); + newmetamethod(MM_MODULO); + newmetamethod(MM_SET); + newmetamethod(MM_GET); + newmetamethod(MM_TYPEOF); + newmetamethod(MM_NEXTI); + newmetamethod(MM_CMP); + newmetamethod(MM_CALL); + newmetamethod(MM_CLONED); + newmetamethod(MM_NEWSLOT); + newmetamethod(MM_DELSLOT); + newmetamethod(MM_TOSTRING); + newmetamethod(MM_NEWMEMBER); + newmetamethod(MM_INHERITED); + + _constructoridx = SQString::Create(this,"constructor"); + _registry = SQTable::Create(this,0); + _consts = SQTable::Create(this,0); + _table_default_delegate = CreateDefaultDelegate(this,_table_default_delegate_funcz); + _array_default_delegate = CreateDefaultDelegate(this,_array_default_delegate_funcz); + _string_default_delegate = CreateDefaultDelegate(this,_string_default_delegate_funcz); + _number_default_delegate = CreateDefaultDelegate(this,_number_default_delegate_funcz); + _closure_default_delegate = CreateDefaultDelegate(this,_closure_default_delegate_funcz); + _generator_default_delegate = CreateDefaultDelegate(this,_generator_default_delegate_funcz); + _thread_default_delegate = CreateDefaultDelegate(this,_thread_default_delegate_funcz); + _class_default_delegate = CreateDefaultDelegate(this,_class_default_delegate_funcz); + _instance_default_delegate = CreateDefaultDelegate(this,_instance_default_delegate_funcz); + _weakref_default_delegate = CreateDefaultDelegate(this,_weakref_default_delegate_funcz); + +} + +SQSharedState::~SQSharedState() +{ + _constructoridx = _null_; + _table(_registry)->Finalize(); + _table(_consts)->Finalize(); + _table(_metamethodsmap)->Finalize(); + _registry = _null_; + _consts = _null_; + _metamethodsmap = _null_; + while(!_systemstrings->empty()) { + _systemstrings->back()=_null_; + _systemstrings->pop_back(); + } + _thread(_root_vm)->Finalize(); + _root_vm = _null_; + _table_default_delegate = _null_; + _array_default_delegate = _null_; + _string_default_delegate = _null_; + _number_default_delegate = _null_; + _closure_default_delegate = _null_; + _generator_default_delegate = _null_; + _thread_default_delegate = _null_; + _class_default_delegate = _null_; + _instance_default_delegate = _null_; + _weakref_default_delegate = _null_; + _refs_table.Finalize(); +#ifndef NO_GARBAGE_COLLECTOR + SQCollectable *t = _gc_chain; + SQCollectable *nx = NULL; + if(t) { + t->_uiRef++; + while(t) { + t->Finalize(); + nx = t->_next; + if(nx) nx->_uiRef++; + if(--t->_uiRef == 0) + t->Release(); + t = nx; + } + } +// assert(_gc_chain==NULL); //just to proove a theory + while(_gc_chain){ + _gc_chain->_uiRef--; + _gc_chain->Release(); + } +#endif + + sq_delete(_types,SQObjectPtrVec); + sq_delete(_systemstrings,SQObjectPtrVec); + sq_delete(_metamethods,SQObjectPtrVec); + sq_delete(_stringtable,SQStringTable); + if(_scratchpad)SQ_FREE(_scratchpad,_scratchpadsize); +} + + +SQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name) +{ + if(type(name) != OT_STRING) + return -1; + SQObjectPtr ret; + if(_table(_metamethodsmap)->Get(name,ret)) { + return _integer(ret); + } + return -1; +} + +#ifndef NO_GARBAGE_COLLECTOR + +void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain) +{ + switch(type(o)){ + case OT_TABLE:_table(o)->Mark(chain);break; + case OT_ARRAY:_array(o)->Mark(chain);break; + case OT_USERDATA:_userdata(o)->Mark(chain);break; + case OT_CLOSURE:_closure(o)->Mark(chain);break; + case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break; + case OT_GENERATOR:_generator(o)->Mark(chain);break; + case OT_THREAD:_thread(o)->Mark(chain);break; + case OT_CLASS:_class(o)->Mark(chain);break; + case OT_INSTANCE:_instance(o)->Mark(chain);break; + default: break; //shutup compiler + } +} + + +SQInteger SQSharedState::CollectGarbage(SQVM *vm) +{ + SQInteger n=0; + SQCollectable *tchain=NULL; + SQVM *vms = _thread(_root_vm); + + vms->Mark(&tchain); + SQInteger x = _table(_thread(_root_vm)->_roottable)->CountUsed(); + _refs_table.Mark(&tchain); + MarkObject(_registry,&tchain); + MarkObject(_consts,&tchain); + MarkObject(_metamethodsmap,&tchain); + MarkObject(_table_default_delegate,&tchain); + MarkObject(_array_default_delegate,&tchain); + MarkObject(_string_default_delegate,&tchain); + MarkObject(_number_default_delegate,&tchain); + MarkObject(_generator_default_delegate,&tchain); + MarkObject(_thread_default_delegate,&tchain); + MarkObject(_closure_default_delegate,&tchain); + MarkObject(_class_default_delegate,&tchain); + MarkObject(_instance_default_delegate,&tchain); + MarkObject(_weakref_default_delegate,&tchain); + + SQCollectable *t = _gc_chain; + SQCollectable *nx = NULL; + if(t) { + t->_uiRef++; + while(t) { + t->Finalize(); + nx = t->_next; + if(nx) nx->_uiRef++; + if(--t->_uiRef == 0) + t->Release(); + t = nx; + n++; + } + } + + t = tchain; + while(t) { + t->UnMark(); + t = t->_next; + } + _gc_chain = tchain; + SQInteger z = _table(_thread(_root_vm)->_roottable)->CountUsed(); + assert(z == x); + return n; +} +#endif + +#ifndef NO_GARBAGE_COLLECTOR +void SQCollectable::AddToChain(SQCollectable **chain,SQCollectable *c) +{ + c->_prev = NULL; + c->_next = *chain; + if(*chain) (*chain)->_prev = c; + *chain = c; +} + +void SQCollectable::RemoveFromChain(SQCollectable **chain,SQCollectable *c) +{ + if(c->_prev) c->_prev->_next = c->_next; + else *chain = c->_next; + if(c->_next) + c->_next->_prev = c->_prev; + c->_next = NULL; + c->_prev = NULL; +} +#endif + +SQChar* SQSharedState::GetScratchPad(SQInteger size) +{ + SQInteger newsize; + if(size>0) { + if(_scratchpadsize < size) { + newsize = size + (size>>1); + _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize); + _scratchpadsize = newsize; + + }else if(_scratchpadsize >= (size<<5)) { + newsize = _scratchpadsize >> 1; + _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize); + _scratchpadsize = newsize; + } + } + return _scratchpad; +} + +RefTable::RefTable() +{ + AllocNodes(4); +} + +void RefTable::Finalize() +{ + RefNode *nodes = _nodes; + for(SQUnsignedInteger n = 0; n < _numofslots; n++) { + nodes->obj = _null_; + nodes++; + } +} + +RefTable::~RefTable() +{ + SQ_FREE(_buckets,(_numofslots * sizeof(RefNode *)) + (_numofslots * sizeof(RefNode))); +} + +#ifndef NO_GARBAGE_COLLECTOR +void RefTable::Mark(SQCollectable **chain) +{ + RefNode *nodes = (RefNode *)_nodes; + for(SQUnsignedInteger n = 0; n < _numofslots; n++) { + if(type(nodes->obj) != OT_NULL) { + SQSharedState::MarkObject(nodes->obj,chain); + } + nodes++; + } +} +#endif + +void RefTable::AddRef(SQObject &obj) +{ + SQHash mainpos; + RefNode *prev; + RefNode *ref = Get(obj,mainpos,&prev,true); + ref->refs++; +} + +SQBool RefTable::Release(SQObject &obj) +{ + SQHash mainpos; + RefNode *prev; + RefNode *ref = Get(obj,mainpos,&prev,false); + if(ref) { + if(--ref->refs == 0) { + SQObjectPtr o = ref->obj; + if(prev) { + prev->next = ref->next; + } + else { + _buckets[mainpos] = ref->next; + } + ref->next = _freelist; + _freelist = ref; + _slotused--; + ref->obj = _null_; + //<>test for shrink? + return SQTrue; + } + } + else { + assert(0); + } + return SQFalse; +} + +void RefTable::Resize(SQUnsignedInteger size) +{ + RefNode **oldbucks = _buckets; + RefNode *t = _nodes; + SQUnsignedInteger oldnumofslots = _numofslots; + AllocNodes(size); + //rehash + SQUnsignedInteger nfound = 0; + for(SQUnsignedInteger n = 0; n < oldnumofslots; n++) { + if(type(t->obj) != OT_NULL) { + //add back; + assert(t->refs != 0); + RefNode *nn = Add(::HashObj(t->obj)&(_numofslots-1),t->obj); + nn->refs = t->refs; + t->obj = _null_; + nfound++; + } + t++; + } + assert(nfound == oldnumofslots); + SQ_FREE(oldbucks,(oldnumofslots * sizeof(RefNode *)) + (oldnumofslots * sizeof(RefNode))); +} + +RefTable::RefNode *RefTable::Add(SQHash mainpos,SQObject &obj) +{ + RefNode *t = _buckets[mainpos]; + RefNode *newnode = _freelist; + newnode->obj = obj; + _buckets[mainpos] = newnode; + _freelist = _freelist->next; + newnode->next = t; + assert(newnode->refs == 0); + _slotused++; + return newnode; +} + +RefTable::RefNode *RefTable::Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add) +{ + RefNode *ref; + mainpos = ::HashObj(obj)&(_numofslots-1); + *prev = NULL; + for (ref = _buckets[mainpos]; ref; ) { + if(_rawval(ref->obj) == _rawval(obj) && type(ref->obj) == type(obj)) + break; + *prev = ref; + ref = ref->next; + } + if(ref == NULL && add) { + if(_numofslots == _slotused) { + assert(_freelist == 0); + Resize(_numofslots*2); + mainpos = ::HashObj(obj)&(_numofslots-1); + } + ref = Add(mainpos,obj); + } + return ref; +} + +void RefTable::AllocNodes(SQUnsignedInteger size) +{ + RefNode **bucks; + RefNode *nodes; + bucks = (RefNode **)SQ_MALLOC((size * sizeof(RefNode *)) + (size * sizeof(RefNode))); + nodes = (RefNode *)&bucks[size]; + RefNode *temp = nodes; + SQUnsignedInteger n; + for(n = 0; n < size - 1; n++) { + bucks[n] = NULL; + temp->refs = 0; + new (&temp->obj) SQObjectPtr; + temp->next = temp+1; + temp++; + } + bucks[n] = NULL; + temp->refs = 0; + new (&temp->obj) SQObjectPtr; + temp->next = NULL; + _freelist = nodes; + _nodes = nodes; + _buckets = bucks; + _slotused = 0; + _numofslots = size; +} +////////////////////////////////////////////////////////////////////////// +//SQStringTable +/* + * The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.) + * http://www.lua.org/copyright.html#4 + * http://www.lua.org/source/4.0.1/src_lstring.c.html + */ + +SQStringTable::SQStringTable() +{ + AllocNodes(4); + _slotused = 0; +} + +SQStringTable::~SQStringTable() +{ + SQ_FREE(_strings,sizeof(SQString*)*_numofslots); + _strings = NULL; +} + +void SQStringTable::AllocNodes(SQInteger size) +{ + _numofslots = size; + _strings = (SQString**)SQ_MALLOC(sizeof(SQString*)*_numofslots); + memset(_strings,0,sizeof(SQString*)*(size_t)_numofslots); +} + +SQString *SQStringTable::Add(const SQChar *news,SQInteger len) +{ + if(len<0) + len = (SQInteger)strlen(news); + SQHash h = ::_hashstr(news,(size_t)len)&(_numofslots-1); + SQString *s; + for (s = _strings[h]; s; s = s->_next){ + if(s->_len == len && (!memcmp(news,s->_val,(size_t)len))) + return s; //found + } + + SQString *t=(SQString *)SQ_MALLOC(len+sizeof(SQString)); + new (t) SQString(news, len); + t->_next = _strings[h]; + _strings[h] = t; + _slotused++; + if (_slotused > _numofslots) /* too crowded? */ + Resize(_numofslots*2); + return t; +} + +SQString::SQString(const SQChar *news, SQInteger len) +{ + memcpy(_val,news,(size_t)len); + _val[len] = '\0'; + _len = len; + _hash = ::_hashstr(news,(size_t)len); + _next = NULL; + _sharedstate = NULL; +} + +void SQStringTable::Resize(SQInteger size) +{ + SQInteger oldsize=_numofslots; + SQString **oldtable=_strings; + AllocNodes(size); + for (SQInteger i=0; i_next; + SQHash h = p->_hash&(_numofslots-1); + p->_next = _strings[h]; + _strings[h] = p; + p = next; + } + } + SQ_FREE(oldtable,oldsize*sizeof(SQString*)); +} + +void SQStringTable::Remove(SQString *bs) +{ + SQString *s; + SQString *prev=NULL; + SQHash h = bs->_hash&(_numofslots - 1); + + for (s = _strings[h]; s; ){ + if(s == bs){ + if(prev) + prev->_next = s->_next; + else + _strings[h] = s->_next; + _slotused--; + SQInteger slen = s->_len; + s->~SQString(); + SQ_FREE(s,sizeof(SQString) + slen); + return; + } + prev = s; + s = s->_next; + } + assert(0);//if this fail something is wrong +} diff --git a/src/3rdparty/squirrel/squirrel/sqstate.h b/src/3rdparty/squirrel/squirrel/sqstate.h new file mode 100644 index 0000000..da6bf9a --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqstate.h @@ -0,0 +1,133 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTATE_H_ +#define _SQSTATE_H_ + +#include "squtils.h" +#include "sqobject.h" +struct SQString; +struct SQTable; +//max number of character for a printed number +#define NUMBER_MAX_CHAR 50 + +struct SQStringTable +{ + SQStringTable(); + ~SQStringTable(); + SQString *Add(const SQChar *,SQInteger len); + void Remove(SQString *); +private: + void Resize(SQInteger size); + void AllocNodes(SQInteger size); + SQString **_strings; + SQUnsignedInteger _numofslots; + SQUnsignedInteger _slotused; +}; + +struct RefTable { + struct RefNode { + SQObjectPtr obj; + SQUnsignedInteger refs; + struct RefNode *next; + }; + RefTable(); + ~RefTable(); + void AddRef(SQObject &obj); + SQBool Release(SQObject &obj); +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); +#endif + void Finalize(); +private: + RefNode *Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add); + RefNode *Add(SQHash mainpos,SQObject &obj); + void Resize(SQUnsignedInteger size); + void AllocNodes(SQUnsignedInteger size); + SQUnsignedInteger _numofslots; + SQUnsignedInteger _slotused; + RefNode *_nodes; + RefNode *_freelist; + RefNode **_buckets; +}; + +#define ADD_STRING(ss,str,len) ss->_stringtable->Add(str,len) +#define REMOVE_STRING(ss,bstr) ss->_stringtable->Remove(bstr) + +struct SQObjectPtr; + +struct SQSharedState +{ + SQSharedState(); + ~SQSharedState(); +public: + SQChar* GetScratchPad(SQInteger size); + SQInteger GetMetaMethodIdxByName(const SQObjectPtr &name); +#ifndef NO_GARBAGE_COLLECTOR + SQInteger CollectGarbage(SQVM *vm); + static void MarkObject(SQObjectPtr &o,SQCollectable **chain); +#endif + SQObjectPtrVec *_metamethods; + SQObjectPtr _metamethodsmap; + SQObjectPtrVec *_systemstrings; + SQObjectPtrVec *_types; + SQStringTable *_stringtable; + RefTable _refs_table; + SQObjectPtr _registry; + SQObjectPtr _consts; + SQObjectPtr _constructoridx; +#ifndef NO_GARBAGE_COLLECTOR + SQCollectable *_gc_chain; +#endif + SQObjectPtr _root_vm; + SQObjectPtr _table_default_delegate; + static SQRegFunction _table_default_delegate_funcz[]; + SQObjectPtr _array_default_delegate; + static SQRegFunction _array_default_delegate_funcz[]; + SQObjectPtr _string_default_delegate; + static SQRegFunction _string_default_delegate_funcz[]; + SQObjectPtr _number_default_delegate; + static SQRegFunction _number_default_delegate_funcz[]; + SQObjectPtr _generator_default_delegate; + static SQRegFunction _generator_default_delegate_funcz[]; + SQObjectPtr _closure_default_delegate; + static SQRegFunction _closure_default_delegate_funcz[]; + SQObjectPtr _thread_default_delegate; + static SQRegFunction _thread_default_delegate_funcz[]; + SQObjectPtr _class_default_delegate; + static SQRegFunction _class_default_delegate_funcz[]; + SQObjectPtr _instance_default_delegate; + static SQRegFunction _instance_default_delegate_funcz[]; + SQObjectPtr _weakref_default_delegate; + static SQRegFunction _weakref_default_delegate_funcz[]; + + SQCOMPILERERROR _compilererrorhandler; + SQPRINTFUNCTION _printfunc; + bool _debuginfo; + bool _notifyallexceptions; +private: + SQChar *_scratchpad; + SQInteger _scratchpadsize; +}; + +#define _sp(s) (_sharedstate->GetScratchPad(s)) +#define _spval (_sharedstate->GetScratchPad(-1)) + +#define _table_ddel _table(_sharedstate->_table_default_delegate) +#define _array_ddel _table(_sharedstate->_array_default_delegate) +#define _string_ddel _table(_sharedstate->_string_default_delegate) +#define _number_ddel _table(_sharedstate->_number_default_delegate) +#define _generator_ddel _table(_sharedstate->_generator_default_delegate) +#define _closure_ddel _table(_sharedstate->_closure_default_delegate) +#define _thread_ddel _table(_sharedstate->_thread_default_delegate) +#define _class_ddel _table(_sharedstate->_class_default_delegate) +#define _instance_ddel _table(_sharedstate->_instance_default_delegate) +#define _weakref_ddel _table(_sharedstate->_weakref_default_delegate) + +extern SQObjectPtr _null_; +extern SQObjectPtr _true_; +extern SQObjectPtr _false_; +extern SQObjectPtr _one_; +extern SQObjectPtr _minusone_; + +bool CompileTypemask(SQIntVec &res,const SQChar *typemask); + +#endif //_SQSTATE_H_ diff --git a/src/3rdparty/squirrel/squirrel/sqstring.h b/src/3rdparty/squirrel/squirrel/sqstring.h new file mode 100644 index 0000000..a5f298e --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqstring.h @@ -0,0 +1,31 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQSTRING_H_ +#define _SQSTRING_H_ + +inline SQHash _hashstr (const SQChar *s, size_t l) +{ + SQHash h = (SQHash)l; /* seed */ + size_t step = (l>>5)|1; /* if string is too long, don't hash all its chars */ + for (; l>=step; l-=step) + h = h ^ ((h<<5)+(h>>2)+(unsigned short)*(s++)); + return h; +} + +struct SQString : public SQRefCounted +{ + SQString(const SQChar *news, SQInteger len); + ~SQString(){} +public: + static SQString *Create(SQSharedState *ss, const SQChar *, SQInteger len = -1 ); + SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); + void Release(); + SQSharedState *_sharedstate; + SQString *_next; //chain for the string table + SQInteger _len; + SQHash _hash; + SQChar _val[1]; +}; + + + +#endif //_SQSTRING_H_ diff --git a/src/3rdparty/squirrel/squirrel/sqtable.cpp b/src/3rdparty/squirrel/squirrel/sqtable.cpp new file mode 100644 index 0000000..60146fe --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqtable.cpp @@ -0,0 +1,201 @@ +/* + * see copyright notice in squirrel.h + */ + +#include "../../../stdafx.h" + +#include "sqpcheader.h" +#include "sqvm.h" +#include "sqtable.h" +#include "sqfuncproto.h" +#include "sqclosure.h" + +#include "../../../safeguards.h" + +SQTable::SQTable(SQSharedState *ss,SQInteger nInitialSize) +{ + SQInteger pow2size=MINPOWER2; + while(nInitialSize>pow2size)pow2size=pow2size<<1; + AllocNodes(pow2size); + _usednodes = 0; + _delegate = NULL; + INIT_CHAIN(); + ADD_TO_CHAIN(&_sharedstate->_gc_chain,this); +} + +void SQTable::Remove(const SQObjectPtr &key) +{ + + _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1)); + if (n) { + n->val = n->key = _null_; + _usednodes--; + Rehash(false); + } +} + +void SQTable::AllocNodes(SQInteger nSize) +{ + _HashNode *nodes=(_HashNode *)SQ_MALLOC(sizeof(_HashNode)*nSize); + for(SQInteger i=0;i= oldsize-oldsize/4) /* using more than 3/4? */ + AllocNodes(oldsize*2); + else if (nelems <= oldsize/4 && /* less than 1/4? */ + oldsize > MINPOWER2) + AllocNodes(oldsize/2); + else if(force) + AllocNodes(oldsize); + else + return; + _usednodes = 0; + for (SQInteger i=0; ikey) != OT_NULL) + NewSlot(old->key,old->val); + } + for(SQInteger k=0;kNewSlot(key,val); + } + nt->SetDelegate(_delegate); + return nt; +} + +bool SQTable::Get(const SQObjectPtr &key,SQObjectPtr &val) +{ + if(type(key) == OT_NULL) + return false; + _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1)); + if (n) { + val = _realval(n->val); + return true; + } + return false; +} +bool SQTable::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val) +{ + assert(type(key) != OT_NULL); + SQHash h = HashObj(key) & (_numofnodes - 1); + _HashNode *n = _Get(key, h); + if (n) { + n->val = val; + return false; + } + _HashNode *mp = &_nodes[h]; + n = mp; + + + //key not found I'll insert it + //main pos is not free + + if(type(mp->key) != OT_NULL) { + n = _firstfree; /* get a free place */ + SQHash mph = HashObj(mp->key) & (_numofnodes - 1); + _HashNode *othern; /* main position of colliding node */ + + if (mp > n && (othern = &_nodes[mph]) != mp){ + /* yes; move colliding node into free position */ + while (othern->next != mp){ + assert(othern->next != NULL); + othern = othern->next; /* find previous */ + } + othern->next = n; /* redo the chain with `n' in place of `mp' */ + n->key = mp->key; + n->val = mp->val;/* copy colliding node into free pos. (mp->next also goes) */ + n->next = mp->next; + mp->key = _null_; + mp->val = _null_; + mp->next = NULL; /* now `mp' is free */ + } + else{ + /* new node will go into free position */ + n->next = mp->next; /* chain new position */ + mp->next = n; + mp = n; + } + } + mp->key = key; + + for (;;) { /* correct `firstfree' */ + if (type(_firstfree->key) == OT_NULL && _firstfree->next == NULL) { + mp->val = val; + _usednodes++; + return true; /* OK; table still has a free place */ + } + else if (_firstfree == _nodes) break; /* cannot decrement from here */ + else (_firstfree)--; + } + Rehash(true); + return NewSlot(key, val); +} + +SQInteger SQTable::Next(bool getweakrefs,const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval) +{ + SQInteger idx = (SQInteger)TranslateIndex(refpos); + while (idx < _numofnodes) { + if(type(_nodes[idx].key) != OT_NULL) { + //first found + _HashNode &n = _nodes[idx]; + outkey = n.key; + outval = getweakrefs?(SQObject)n.val:_realval(n.val); + //return idx for the next iteration + return ++idx; + } + ++idx; + } + //nothing to iterate anymore + return -1; +} + + +bool SQTable::Set(const SQObjectPtr &key, const SQObjectPtr &val) +{ + _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1)); + if (n) { + n->val = val; + return true; + } + return false; +} + +void SQTable::_ClearNodes() +{ + for(SQInteger i = 0;i < _numofnodes; i++) { _nodes[i].key = _null_; _nodes[i].val = _null_; } +} + +void SQTable::Finalize() +{ + _ClearNodes(); + SetDelegate(NULL); +} + +void SQTable::Clear() +{ + _ClearNodes(); + _usednodes = 0; + Rehash(true); +} diff --git a/src/3rdparty/squirrel/squirrel/sqtable.h b/src/3rdparty/squirrel/squirrel/sqtable.h new file mode 100644 index 0000000..52d9ba4 --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqtable.h @@ -0,0 +1,91 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQTABLE_H_ +#define _SQTABLE_H_ +/* + * The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.) + * http://www.lua.org/copyright.html#4 + * http://www.lua.org/source/4.0.1/src_ltable.c.html + */ + +#include "sqstring.h" + + +#define hashptr(p) ((SQHash)(((SQInteger)p) >> 3)) + +inline SQHash HashObj(const SQObjectPtr &key) +{ + switch(type(key)) { + case OT_STRING: return _string(key)->_hash; + case OT_FLOAT: return (SQHash)((SQInteger)_float(key)); + case OT_BOOL: case OT_INTEGER: return (SQHash)((SQInteger)_integer(key)); + default: return hashptr(key._unVal.pRefCounted); + } +} + +struct SQTable : public SQDelegable +{ +private: + struct _HashNode + { + _HashNode() { next = NULL; } + SQObjectPtr val; + SQObjectPtr key; + _HashNode *next; + }; + _HashNode *_firstfree; + _HashNode *_nodes; + SQInteger _numofnodes; + SQInteger _usednodes; + +/////////////////////////// + void AllocNodes(SQInteger nSize); + void Rehash(bool force); + SQTable(SQSharedState *ss, SQInteger nInitialSize); + void _ClearNodes(); +public: + static SQTable* Create(SQSharedState *ss,SQInteger nInitialSize) + { + SQTable *newtable = (SQTable*)SQ_MALLOC(sizeof(SQTable)); + new (newtable) SQTable(ss, nInitialSize); + newtable->_delegate = NULL; + return newtable; + } + void Finalize(); + SQTable *Clone(); + ~SQTable() + { + SetDelegate(NULL); + REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); + for (SQInteger i = 0; i < _numofnodes; i++) _nodes[i].~_HashNode(); + SQ_FREE(_nodes, _numofnodes * sizeof(_HashNode)); + } +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); +#endif + inline _HashNode *_Get(const SQObjectPtr &key,SQHash hash) + { + _HashNode *n = &_nodes[hash]; + do{ + if(_rawval(n->key) == _rawval(key) && type(n->key) == type(key)){ + return n; + } + }while((n = n->next)); + return NULL; + } + bool Get(const SQObjectPtr &key,SQObjectPtr &val); + void Remove(const SQObjectPtr &key); + bool Set(const SQObjectPtr &key, const SQObjectPtr &val); + //returns true if a new slot has been created false if it was already present + bool NewSlot(const SQObjectPtr &key,const SQObjectPtr &val); + SQInteger Next(bool getweakrefs,const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); + + SQInteger CountUsed(){ return _usednodes;} + void Clear(); + void Release() + { + sq_delete(this, SQTable); + } + +}; + +#endif //_SQTABLE_H_ diff --git a/src/3rdparty/squirrel/squirrel/squserdata.h b/src/3rdparty/squirrel/squirrel/squserdata.h new file mode 100644 index 0000000..3bf1a9d --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/squserdata.h @@ -0,0 +1,37 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQUSERDATA_H_ +#define _SQUSERDATA_H_ + +struct SQUserData : SQDelegable +{ + SQUserData(SQSharedState *ss, SQInteger size){ _delegate = 0; _hook = NULL; INIT_CHAIN(); ADD_TO_CHAIN(&_ss(this)->_gc_chain, this); _size = size; _typetag = 0; +} + ~SQUserData() + { + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain, this); + SetDelegate(NULL); + } + static SQUserData* Create(SQSharedState *ss, SQInteger size) + { + SQUserData* ud = (SQUserData*)SQ_MALLOC(sizeof(SQUserData)+(size-1)); + new (ud) SQUserData(ss, size); + return ud; + } +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); + void Finalize(){SetDelegate(NULL);} +#endif + void Release() { + if (_hook) _hook(_val,_size); + SQInteger tsize = _size - 1; + this->~SQUserData(); + SQ_FREE(this, sizeof(SQUserData) + tsize); + } + + SQInteger _size; + SQRELEASEHOOK _hook; + SQUserPointer _typetag; + SQChar _val[1]; +}; + +#endif //_SQUSERDATA_H_ diff --git a/src/3rdparty/squirrel/squirrel/squtils.h b/src/3rdparty/squirrel/squirrel/squtils.h new file mode 100644 index 0000000..28c6cbe --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/squtils.h @@ -0,0 +1,112 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQUTILS_H_ +#define _SQUTILS_H_ + +void *sq_vm_malloc(SQUnsignedInteger size); +void *sq_vm_realloc(void *p,SQUnsignedInteger oldsize,SQUnsignedInteger size); +void sq_vm_free(void *p,SQUnsignedInteger size); + +#define sq_new(__ptr,__type) {__ptr=(__type *)sq_vm_malloc(sizeof(__type));new (__ptr) __type;} +#define sq_delete(__ptr,__type) {__ptr->~__type();sq_vm_free(__ptr,sizeof(__type));} +#define SQ_MALLOC(__size) sq_vm_malloc((__size)); +#define SQ_FREE(__ptr,__size) sq_vm_free((__ptr),(__size)); +#define SQ_REALLOC(__ptr,__oldsize,__size) sq_vm_realloc((__ptr),(__oldsize),(__size)); + +//sqvector mini vector class, supports objects by value +template class sqvector +{ +public: + sqvector() + { + _vals = NULL; + _size = 0; + _allocated = 0; + } + sqvector(const sqvector& v) + { + copy(v); + } + void copy(const sqvector& v) + { + resize(v._size); + for(SQUnsignedInteger i = 0; i < v._size; i++) { + new ((void *)&_vals[i]) T(v._vals[i]); + } + _size = v._size; + } + ~sqvector() + { + if(_allocated) { + /* Break freeing loops, if this vector (indirectly) links to itself. */ + size_t allocated_size = _allocated * sizeof(T); + _allocated = 0; + + for(size_t i = 0; i < _size; i++) + _vals[i].~T(); + SQ_FREE(_vals, allocated_size); + } + } + void reserve(SQUnsignedInteger newsize) { _realloc(newsize); } + void resize(SQUnsignedInteger newsize, const T& fill = T()) + { + if(newsize > _allocated) + _realloc(newsize); + if(newsize > _size) { + while(_size < newsize) { + new ((void *)&_vals[_size]) T(fill); + _size++; + } + } + else{ + for(SQUnsignedInteger i = newsize; i < _size; i++) { + _vals[i].~T(); + } + _size = (size_t)newsize; + } + } + void shrinktofit() { if(_size > 4) { _realloc(_size); } } + T& top() const { return _vals[_size - 1]; } + inline SQUnsignedInteger size() const { return _size; } + bool empty() const { return (_size <= 0); } + inline T &push_back(const T& val = T()) + { + if(_allocated <= _size) + _realloc(_size * 2); + return *(new ((void *)&_vals[_size++]) T(val)); + } + inline void pop_back() + { + _size--; _vals[_size].~T(); + } + void insert(SQUnsignedInteger idx, const T& val) + { + resize(_size + 1); + for(SQUnsignedInteger i = _size - 1; i > idx; i--) { + _vals[i] = _vals[i - 1]; + } + _vals[idx] = val; + } + void remove(SQUnsignedInteger idx) + { + _vals[idx].~T(); + if(idx < (_size - 1)) { + memmove(&_vals[idx], &_vals[idx+1], sizeof(T) * (_size - (size_t)idx - 1)); + } + _size--; + } + SQUnsignedInteger capacity() { return _allocated; } + inline T &back() const { return _vals[_size - 1]; } + inline T& operator[](SQUnsignedInteger pos) const{ assert(pos < _allocated); return _vals[pos]; } + T* _vals; +private: + void _realloc(SQUnsignedInteger newsize) + { + newsize = (newsize > 0)?newsize:4; + _vals = (T*)SQ_REALLOC(_vals, _allocated * sizeof(T), newsize * sizeof(T)); + _allocated = (size_t)newsize; + } + size_t _size; + size_t _allocated; +}; + +#endif //_SQUTILS_H_ diff --git a/src/3rdparty/squirrel/squirrel/sqvm.cpp b/src/3rdparty/squirrel/squirrel/sqvm.cpp new file mode 100644 index 0000000..973002b --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqvm.cpp @@ -0,0 +1,1608 @@ +/* + * see copyright notice in squirrel.h + */ + +#include "../../../stdafx.h" + +#include +#include "sqpcheader.h" +#include +#include "sqopcodes.h" +#include "sqfuncproto.h" +#include "sqvm.h" +#include "sqclosure.h" +#include "sqstring.h" +#include "sqtable.h" +#include "squserdata.h" +#include "sqarray.h" +#include "sqclass.h" + +#include "../../../string_func.h" + +#include "../../../safeguards.h" + +#define TOP() (_stack._vals[_top-1]) + +#define CLEARSTACK(_last_top) { if((_last_top) >= _top) ClearStack(_last_top); } +void SQVM::ClearStack(SQInteger last_top) +{ + SQObjectType tOldType; + SQObjectValue unOldVal; + while (last_top >= _top) { + SQObjectPtr &o = _stack._vals[last_top--]; + tOldType = o._type; + unOldVal = o._unVal; + o._type = OT_NULL; + o._unVal.pUserPointer = NULL; + __Release(tOldType,unOldVal); + } +} + +bool SQVM::BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2) +{ + SQInteger res; + SQInteger i1 = _integer(o1), i2 = _integer(o2); + if((type(o1)==OT_INTEGER) && (type(o2)==OT_INTEGER)) + { + switch(op) { + case BW_AND: res = i1 & i2; break; + case BW_OR: res = i1 | i2; break; + case BW_XOR: res = i1 ^ i2; break; + case BW_SHIFTL: res = i1 << i2; break; + case BW_SHIFTR: res = i1 >> i2; break; + case BW_USHIFTR:res = (SQInteger)(*((SQUnsignedInteger*)&i1) >> i2); break; + default: { Raise_Error("internal vm error bitwise op failed"); return false; } + } + } + else { Raise_Error("bitwise op between '%s' and '%s'",GetTypeName(o1),GetTypeName(o2)); return false;} + trg = res; + return true; +} + +bool SQVM::ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2) +{ + if(sq_isnumeric(o1) && sq_isnumeric(o2)) { + if((type(o1)==OT_INTEGER) && (type(o2)==OT_INTEGER)) { + SQInteger res, i1 = _integer(o1), i2 = _integer(o2); + switch(op) { + case '+': res = i1 + i2; break; + case '-': res = i1 - i2; break; + case '/': if(i2 == 0) { Raise_Error("division by zero"); return false; } + res = i1 / i2; + break; + case '*': res = i1 * i2; break; + case '%': if(i2 == 0) { Raise_Error("modulo by zero"); return false; } + res = i1 % i2; + break; + default: res = 0xDEADBEEF; + } + trg = res; + }else{ + SQFloat res, f1 = tofloat(o1), f2 = tofloat(o2); + switch(op) { + case '+': res = f1 + f2; break; + case '-': res = f1 - f2; break; + case '/': res = f1 / f2; break; + case '*': res = f1 * f2; break; + case '%': res = SQFloat(fmod((double)f1,(double)f2)); break; + default: res = 0x0f; + } + trg = res; + } + } else { + if(op == '+' && (type(o1) == OT_STRING || type(o2) == OT_STRING)){ + if(!StringCat(o1, o2, trg)) return false; + } + else if(!ArithMetaMethod(op,o1,o2,trg)) { + Raise_Error("arith op %c on between '%s' and '%s'",op,GetTypeName(o1),GetTypeName(o2)); return false; + } + } + return true; +} + +SQVM::SQVM(SQSharedState *ss) +{ + _sharedstate=ss; + _suspended = SQFalse; + _suspended_target=-1; + _suspended_root = SQFalse; + _suspended_traps=0; + _foreignptr=NULL; + _nnativecalls=0; + _lasterror = _null_; + _errorhandler = _null_; + _debughook = _null_; + _can_suspend = false; + _in_stackoverflow = false; + _ops_till_suspend = 0; + _callsstack = NULL; + _callsstacksize = 0; + _alloccallsstacksize = 0; + _top = 0; + _stackbase = 0; + ci = NULL; + INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); +} + +void SQVM::Finalize() +{ + _roottable = _null_; + _lasterror = _null_; + _errorhandler = _null_; + _debughook = _null_; + temp_reg = _null_; + _callstackdata.resize(0); + SQInteger size=_stack.size(); + for(SQInteger i=size - 1;i>=0;i--) + _stack[i]=_null_; +} + +SQVM::~SQVM() +{ + Finalize(); + //sq_free(_callsstack,_alloccallsstacksize*sizeof(CallInfo)); + REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); +} + +bool SQVM::ArithMetaMethod(SQInteger op,const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &dest) +{ + SQMetaMethod mm; + switch(op){ + case '+': mm=MT_ADD; break; + case '-': mm=MT_SUB; break; + case '/': mm=MT_DIV; break; + case '*': mm=MT_MUL; break; + case '%': mm=MT_MODULO; break; + default: mm = MT_ADD; assert(0); break; //shutup compiler + } + if(is_delegable(o1) && _delegable(o1)->_delegate) { + Push(o1);Push(o2); + return CallMetaMethod(_delegable(o1),mm,2,dest); + } + return false; +} + +bool SQVM::NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o) +{ + + switch(type(o)) { + case OT_INTEGER: + trg = -_integer(o); + return true; + case OT_FLOAT: + trg = -_float(o); + return true; + case OT_TABLE: + case OT_USERDATA: + case OT_INSTANCE: + if(_delegable(o)->_delegate) { + Push(o); + if(CallMetaMethod(_delegable(o), MT_UNM, 1, temp_reg)) { + trg = temp_reg; + return true; + } + } + default:break; //shutup compiler + } + Raise_Error("attempt to negate a %s", GetTypeName(o)); + return false; +} + +#define _RET_SUCCEED(exp) { result = (exp); return true; } +bool SQVM::ObjCmp(const SQObjectPtr &o1,const SQObjectPtr &o2,SQInteger &result) +{ + if(type(o1)==type(o2)){ + if(_rawval(o1)==_rawval(o2))_RET_SUCCEED(0); + SQObjectPtr res; + switch(type(o1)){ + case OT_STRING: + _RET_SUCCEED(strcmp(_stringval(o1),_stringval(o2))); + case OT_INTEGER: + /* FS#3954: wrong integer comparison */ + _RET_SUCCEED((_integer(o1)<_integer(o2))?-1:(_integer(o1)==_integer(o2))?0:1); + case OT_FLOAT: + _RET_SUCCEED((_float(o1)<_float(o2))?-1:1); + case OT_TABLE: + case OT_USERDATA: + case OT_INSTANCE: + if(_delegable(o1)->_delegate) { + Push(o1);Push(o2); + if(CallMetaMethod(_delegable(o1),MT_CMP,2,res)) { + if(type(res) != OT_INTEGER) { + Raise_Error("_cmp must return an integer"); + return false; + } + _RET_SUCCEED(_integer(res)) + } + } + //continues through (no break needed) + default: + _RET_SUCCEED( _userpointer(o1) < _userpointer(o2)?-1:1 ); + } + assert(0); + + } + else{ + if(sq_isnumeric(o1) && sq_isnumeric(o2)){ + if((type(o1)==OT_INTEGER) && (type(o2)==OT_FLOAT)) { + if( _integer(o1)==_float(o2) ) { _RET_SUCCEED(0); } + else if( _integer(o1)<_float(o2) ) { _RET_SUCCEED(-1); } + _RET_SUCCEED(1); + } + else{ + if( _float(o1)==_integer(o2) ) { _RET_SUCCEED(0); } + else if( _float(o1)<_integer(o2) ) { _RET_SUCCEED(-1); } + _RET_SUCCEED(1); + } + } + else if(type(o1)==OT_NULL) {_RET_SUCCEED(-1);} + else if(type(o2)==OT_NULL) {_RET_SUCCEED(1);} + else { Raise_CompareError(o1,o2); return false; } + + } + assert(0); + _RET_SUCCEED(0); //cannot happen +} + +bool SQVM::CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res) +{ + SQInteger r; + if(ObjCmp(o1,o2,r)) { + switch(op) { + case CMP_G: res = (r > 0)?_true_:_false_; return true; + case CMP_GE: res = (r >= 0)?_true_:_false_; return true; + case CMP_L: res = (r < 0)?_true_:_false_; return true; + case CMP_LE: res = (r <= 0)?_true_:_false_; return true; + + } + assert(0); + } + return false; +} + +void SQVM::ToString(const SQObjectPtr &o,SQObjectPtr &res) +{ + char buf[64]; + switch(type(o)) { + case OT_STRING: + res = o; + return; + case OT_FLOAT: + seprintf(buf, lastof(buf),"%g",_float(o)); + break; + case OT_INTEGER: + seprintf(buf, lastof(buf),OTTD_PRINTF64,_integer(o)); + break; + case OT_BOOL: + seprintf(buf, lastof(buf),_integer(o)?"true":"false"); + break; + case OT_TABLE: + case OT_USERDATA: + case OT_INSTANCE: + if(_delegable(o)->_delegate) { + Push(o); + if(CallMetaMethod(_delegable(o),MT_TOSTRING,1,res)) { + if(type(res) == OT_STRING) + return; + //else keeps going to the default + } + } + default: + seprintf(buf, lastof(buf),"(%s : 0x%p)",GetTypeName(o),(void*)_rawval(o)); + } + res = SQString::Create(_ss(this),buf); +} + + +bool SQVM::StringCat(const SQObjectPtr &str,const SQObjectPtr &obj,SQObjectPtr &dest) +{ + SQObjectPtr a, b; + ToString(str, a); + ToString(obj, b); + SQInteger l = _string(a)->_len , ol = _string(b)->_len; + SQChar *s = _sp(l + ol + 1); + memcpy(s, _stringval(a), (size_t)l); + memcpy(s + l, _stringval(b), (size_t)ol); + dest = SQString::Create(_ss(this), _spval, l + ol); + return true; +} + +void SQVM::TypeOf(const SQObjectPtr &obj1,SQObjectPtr &dest) +{ + if(is_delegable(obj1) && _delegable(obj1)->_delegate) { + Push(obj1); + if(CallMetaMethod(_delegable(obj1),MT_TYPEOF,1,dest)) + return; + } + dest = SQString::Create(_ss(this),GetTypeName(obj1)); +} + +bool SQVM::Init(SQVM *friendvm, SQInteger stacksize) +{ + _stack.resize(stacksize); + _alloccallsstacksize = 4; + _callstackdata.resize(_alloccallsstacksize); + _callsstacksize = 0; + _callsstack = &_callstackdata[0]; + _stackbase = 0; + _top = 0; + if(!friendvm) + _roottable = SQTable::Create(_ss(this), 0); + else { + _roottable = friendvm->_roottable; + _errorhandler = friendvm->_errorhandler; + _debughook = friendvm->_debughook; + } + + sq_base_register(this); + return true; +} + +extern SQInstructionDesc g_InstrDesc[]; + +bool SQVM::StartCall(SQClosure *closure,SQInteger target,SQInteger args,SQInteger stackbase,bool tailcall) +{ + SQFunctionProto *func = _funcproto(closure->_function); + + const SQInteger paramssize = func->_nparameters; + const SQInteger newtop = stackbase + func->_stacksize; + SQInteger nargs = args; + if (paramssize != nargs) { + SQInteger ndef = func->_ndefaultparams; + SQInteger diff; + if(ndef && nargs < paramssize && (diff = paramssize - nargs) <= ndef) { + for(SQInteger n = ndef - diff; n < ndef; n++) { + _stack._vals[stackbase + (nargs++)] = closure->_defaultparams[n]; + } + } + else if(func->_varparams) + { + if (nargs < paramssize) { + Raise_Error("wrong number of parameters"); + return false; + } + for(SQInteger n = 0; n < nargs - paramssize; n++) { + _vargsstack.push_back(_stack._vals[stackbase+paramssize+n]); + _stack._vals[stackbase+paramssize+n] = _null_; + } + } + else { + Raise_Error("wrong number of parameters"); + return false; + } + } + + if(type(closure->_env) == OT_WEAKREF) { + _stack._vals[stackbase] = _weakref(closure->_env)->_obj; + } + + if (!tailcall) { + CallInfo lc; + memset(&lc, 0, sizeof(lc)); + lc._generator = NULL; + lc._etraps = 0; + lc._prevstkbase = (SQInt32) ( stackbase - _stackbase ); + lc._target = (SQInt32) target; + lc._prevtop = (SQInt32) (_top - _stackbase); + lc._ncalls = 1; + lc._root = SQFalse; + PUSH_CALLINFO(this, lc); + } + else { + ci->_ncalls++; + } + ci->_vargs.size = (SQInt32)(nargs - paramssize); + ci->_vargs.base = (SQInt32)(_vargsstack.size()-(ci->_vargs.size)); + ci->_closure = closure; + ci->_literals = func->_literals; + ci->_ip = func->_instructions; + //grows the stack if needed + if (((SQUnsignedInteger)newtop + (func->_stacksize<<1)) > _stack.size()) { + _stack.resize(_stack.size() + (func->_stacksize<<1)); + } + + _top = newtop; + _stackbase = stackbase; + if (type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure)) + CallDebugHook('c'); + return true; +} + +bool SQVM::Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval) +{ + if (type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure)) + for(SQInteger i=0;i_ncalls;i++) + CallDebugHook('r'); + + SQBool broot = ci->_root; + SQInteger last_top = _top; + SQInteger target = ci->_target; + SQInteger oldstackbase = _stackbase; + _stackbase -= ci->_prevstkbase; + _top = _stackbase + ci->_prevtop; + if(ci->_vargs.size) PopVarArgs(ci->_vargs); + POP_CALLINFO(this); + if (broot) { + if (_arg0 != MAX_FUNC_STACKSIZE) retval = _stack._vals[oldstackbase+_arg1]; + else retval = _null_; + } + else { + if(target != -1) { //-1 is when a class contructor ret value has to be ignored + if (_arg0 != MAX_FUNC_STACKSIZE) + STK(target) = _stack._vals[oldstackbase+_arg1]; + else + STK(target) = _null_; + } + } + + while (last_top > oldstackbase) _stack._vals[last_top--].Null(); + assert(oldstackbase >= _stackbase); + return broot?true:false; +} + +#define _RET_ON_FAIL(exp) { if(!exp) return false; } + +bool SQVM::LOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr) +{ + _RET_ON_FAIL(ARITH_OP( op , target, a, incr)); + a = target; + return true; +} + +bool SQVM::PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr) +{ + SQObjectPtr trg; + _RET_ON_FAIL(ARITH_OP( op , trg, a, incr)); + target = a; + a = trg; + return true; +} + +bool SQVM::DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix) +{ + SQObjectPtr tmp, tself = self, tkey = key; + if (!Get(tself, tkey, tmp, false, true)) { Raise_IdxError(tkey); return false; } + _RET_ON_FAIL(ARITH_OP( op , target, tmp, incr)) + Set(tself, tkey, target,true); + if (postfix) target = tmp; + return true; +} + +#define arg0 (_i_._arg0) +#define arg1 (_i_._arg1) +#define sarg1 (*(const_cast(&_i_._arg1))) +#define arg2 (_i_._arg2) +#define arg3 (_i_._arg3) +#define sarg3 ((SQInteger)*((const signed char *)&_i_._arg3)) + +SQRESULT SQVM::Suspend() +{ + if (_suspended) + return sq_throwerror(this, "cannot suspend an already suspended vm"); + if (_nnativecalls!=2) + return sq_throwerror(this, "cannot suspend through native calls/metamethods"); + return SQ_SUSPEND_FLAG; +} + +void SQVM::PopVarArgs(VarArgs &vargs) +{ + for(SQInteger n = 0; n< vargs.size; n++) + _vargsstack.pop_back(); +} + +#define _FINISH(howmuchtojump) {jump = howmuchtojump; return true; } +bool SQVM::FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr +&o3,SQObjectPtr &o4,SQInteger arg_2,int exitpos,int &jump) +{ + SQInteger nrefidx; + switch(type(o1)) { + case OT_TABLE: + if((nrefidx = _table(o1)->Next(false,o4, o2, o3)) == -1) _FINISH(exitpos); + o4 = (SQInteger)nrefidx; _FINISH(1); + case OT_ARRAY: + if((nrefidx = _array(o1)->Next(o4, o2, o3)) == -1) _FINISH(exitpos); + o4 = (SQInteger) nrefidx; _FINISH(1); + case OT_STRING: + if((nrefidx = _string(o1)->Next(o4, o2, o3)) == -1)_FINISH(exitpos); + o4 = (SQInteger)nrefidx; _FINISH(1); + case OT_CLASS: + if((nrefidx = _class(o1)->Next(o4, o2, o3)) == -1)_FINISH(exitpos); + o4 = (SQInteger)nrefidx; _FINISH(1); + case OT_USERDATA: + case OT_INSTANCE: + if(_delegable(o1)->_delegate) { + SQObjectPtr itr; + Push(o1); + Push(o4); + if(CallMetaMethod(_delegable(o1), MT_NEXTI, 2, itr)){ + o4 = o2 = itr; + if(type(itr) == OT_NULL) _FINISH(exitpos); + if(!Get(o1, itr, o3, false,false)) { + Raise_Error("_nexti returned an invalid idx"); + return false; + } + _FINISH(1); + } + Raise_Error("_nexti failed"); + return false; + } + break; + case OT_GENERATOR: + if(_generator(o1)->_state == SQGenerator::eDead) _FINISH(exitpos); + if(_generator(o1)->_state == SQGenerator::eSuspended) { + SQInteger idx = 0; + if(type(o4) == OT_INTEGER) { + idx = _integer(o4) + 1; + } + o2 = idx; + o4 = idx; + _generator(o1)->Resume(this, arg_2+1); + _FINISH(0); + } + /* FALL THROUGH */ + default: + Raise_Error("cannot iterate %s", GetTypeName(o1)); + } + return false; //cannot be hit(just to avoid warnings) +} + +bool SQVM::DELEGATE_OP(SQObjectPtr &trg,SQObjectPtr &o1,SQObjectPtr &o2) +{ + if(type(o1) != OT_TABLE) { Raise_Error("delegating a '%s'", GetTypeName(o1)); return false; } + switch(type(o2)) { + case OT_TABLE: + if(!_table(o1)->SetDelegate(_table(o2))){ + Raise_Error("delegate cycle detected"); + return false; + } + break; + case OT_NULL: + _table(o1)->SetDelegate(NULL); + break; + default: + Raise_Error("using '%s' as delegate", GetTypeName(o2)); + return false; + break; + } + trg = o1; + return true; +} +#define COND_LITERAL (arg3!=0?ci->_literals[arg1]:STK(arg1)) + +#define _GUARD(exp) { if(!exp) { Raise_Error(_lasterror); SQ_THROW();} } + +#define SQ_THROW() { goto exception_trap; } + +bool SQVM::CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func) +{ + SQInteger nouters; + SQClosure *closure = SQClosure::Create(_ss(this), func); + if((nouters = func->_noutervalues)) { + closure->_outervalues.reserve(nouters); + for(SQInteger i = 0; i_outervalues[i]; + switch(v._type){ + case otSYMBOL: + closure->_outervalues.push_back(_null_); + if(!Get(_stack._vals[_stackbase]/*STK(0)*/, v._src, closure->_outervalues.top(), false,true)) + {Raise_IdxError(v._src); return false; } + break; + case otLOCAL: + closure->_outervalues.push_back(_stack._vals[_stackbase+_integer(v._src)]); + break; + case otOUTER: + closure->_outervalues.push_back(_closure(ci->_closure)->_outervalues[_integer(v._src)]); + break; + } + } + } + SQInteger ndefparams; + if((ndefparams = func->_ndefaultparams)) { + closure->_defaultparams.reserve(ndefparams); + for(SQInteger i = 0; i < ndefparams; i++) { + SQInteger spos = func->_defaultparams[i]; + closure->_defaultparams.push_back(_stack._vals[_stackbase + spos]); + } + } + target = closure; + return true; + +} + +bool SQVM::GETVARGV_OP(SQObjectPtr &target,SQObjectPtr &index,CallInfo *ci) +{ + if(ci->_vargs.size == 0) { + Raise_Error("the function doesn't have var args"); + return false; + } + if(!sq_isnumeric(index)){ + Raise_Error("indexing 'vargv' with %s",GetTypeName(index)); + return false; + } + SQInteger idx = tointeger(index); + if(idx < 0 || idx >= ci->_vargs.size){ Raise_Error("vargv index out of range"); return false; } + target = _vargsstack[ci->_vargs.base+idx]; + return true; +} + +bool SQVM::CLASS_OP(SQObjectPtr &target,SQInteger baseclass,SQInteger attributes) +{ + SQClass *base = NULL; + SQObjectPtr attrs; + if(baseclass != -1) { + if(type(_stack._vals[_stackbase+baseclass]) != OT_CLASS) { Raise_Error("trying to inherit from a %s",GetTypeName(_stack._vals[_stackbase+baseclass])); return false; } + base = _class(_stack._vals[_stackbase + baseclass]); + } + if(attributes != MAX_FUNC_STACKSIZE) { + attrs = _stack._vals[_stackbase+attributes]; + } + target = SQClass::Create(_ss(this),base); + if(type(_class(target)->_metamethods[MT_INHERITED]) != OT_NULL) { + int nparams = 2; + SQObjectPtr ret; + Push(target); Push(attrs); + Call(_class(target)->_metamethods[MT_INHERITED],nparams,_top - nparams, ret, false, false); + Pop(nparams); + } + _class(target)->_attributes = attrs; + return true; +} + + + +bool SQVM::IsEqual(SQObjectPtr &o1,SQObjectPtr &o2,bool &res) +{ + if(type(o1) == type(o2)) { + res = ((_rawval(o1) == _rawval(o2)?true:false)); + } + else { + if(sq_isnumeric(o1) && sq_isnumeric(o2)) { + SQInteger cmpres; + if(!ObjCmp(o1, o2,cmpres)) return false; + res = (cmpres == 0); + } + else { + res = false; + } + } + return true; +} + +bool SQVM::IsFalse(SQObjectPtr &o) +{ + if(((type(o) & SQOBJECT_CANBEFALSE) && ( (type(o) == OT_FLOAT) && (_float(o) == SQFloat(0.0)) )) + || (_integer(o) == 0) ) { //OT_NULL|OT_INTEGER|OT_BOOL + return true; + } + return false; +} + +bool SQVM::GETPARENT_OP(SQObjectPtr &o,SQObjectPtr &target) +{ + switch(type(o)) { + case OT_TABLE: target = _table(o)->_delegate?SQObjectPtr(_table(o)->_delegate):_null_; + break; + case OT_CLASS: target = _class(o)->_base?_class(o)->_base:_null_; + break; + default: + Raise_Error("the %s type doesn't have a parent slot", GetTypeName(o)); + return false; + } + return true; +} + +bool SQVM::Execute(SQObjectPtr &closure, SQInteger target, SQInteger nargs, SQInteger stackbase,SQObjectPtr &outres, SQBool raiseerror,ExecutionType et) +{ + if ((_nnativecalls + 1) > MAX_NATIVE_CALLS) { Raise_Error("Native stack overflow"); return false; } + _nnativecalls++; + AutoDec ad(&_nnativecalls); + SQInteger traps = 0; + //temp_reg vars for OP_CALL + SQInteger ct_target; + SQInteger ct_stackbase; + bool ct_tailcall; + + switch(et) { + case ET_CALL: { + SQInteger last_top = _top; + temp_reg = closure; + if(!StartCall(_closure(temp_reg), _top - nargs, nargs, stackbase, false)) { + //call the handler if there are no calls in the stack, if not relies on the previous node + if(ci == NULL) CallErrorHandler(_lasterror); + return false; + } + if (_funcproto(_closure(temp_reg)->_function)->_bgenerator) { + //SQFunctionProto *f = _funcproto(_closure(temp_reg)->_function); + SQGenerator *gen = SQGenerator::Create(_ss(this), _closure(temp_reg)); + _GUARD(gen->Yield(this)); + Return(1, ci->_target, temp_reg); + outres = gen; + CLEARSTACK(last_top); + return true; + } + ci->_root = SQTrue; + } + break; + case ET_RESUME_GENERATOR: _generator(closure)->Resume(this, target); ci->_root = SQTrue; traps += ci->_etraps; break; + case ET_RESUME_VM: + case ET_RESUME_THROW_VM: + traps = _suspended_traps; + ci->_root = _suspended_root; + ci->_vargs = _suspend_varargs; + _suspended = SQFalse; + if(et == ET_RESUME_THROW_VM) { SQ_THROW(); } + break; + case ET_RESUME_OPENTTD: + traps = _suspended_traps; + _suspended = SQFalse; + break; + } + +exception_restore: + // + { + for(;;) + { + DecreaseOps(1); + if (ShouldSuspend()) { _suspended = SQTrue; _suspended_traps = traps; return true; } + + const SQInstruction &_i_ = *ci->_ip++; + //dumpstack(_stackbase); + //printf("%s %d %d %d %d\n",g_InstrDesc[_i_.op].name,arg0,arg1,arg2,arg3); + switch(_i_.op) + { + case _OP_LINE: + if(type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure)) + CallDebugHook('l',arg1); + continue; + case _OP_LOAD: TARGET = ci->_literals[arg1]; continue; + case _OP_LOADINT: TARGET = (SQInteger)arg1; continue; + case _OP_LOADFLOAT: TARGET = *((const SQFloat *)&arg1); continue; + case _OP_DLOAD: TARGET = ci->_literals[arg1]; STK(arg2) = ci->_literals[arg3];continue; + case _OP_TAILCALL: + temp_reg = STK(arg1); + if (type(temp_reg) == OT_CLOSURE && !_funcproto(_closure(temp_reg)->_function)->_bgenerator){ + ct_tailcall = true; + if(ci->_vargs.size) PopVarArgs(ci->_vargs); + for (SQInteger i = 0; i < arg3; i++) STK(i) = STK(arg2 + i); + ct_target = ci->_target; + ct_stackbase = _stackbase; + goto common_call; + } + /* FALL THROUGH */ + case _OP_CALL: { + ct_tailcall = false; + ct_target = arg0; + temp_reg = STK(arg1); + ct_stackbase = _stackbase+arg2; + +common_call: + SQObjectPtr clo = temp_reg; + SQInteger last_top = _top; + switch (type(clo)) { + case OT_CLOSURE:{ + _GUARD(StartCall(_closure(clo), ct_target, arg3, ct_stackbase, ct_tailcall)); + if (_funcproto(_closure(clo)->_function)->_bgenerator) { + SQGenerator *gen = SQGenerator::Create(_ss(this), _closure(clo)); + _GUARD(gen->Yield(this)); + Return(1, ct_target, clo); + STK(ct_target) = gen; + } + CLEARSTACK(last_top); + } + continue; + case OT_NATIVECLOSURE: { + bool suspend; + _suspended_target = ct_target; + try { + _GUARD(CallNative(_nativeclosure(clo), arg3, ct_stackbase, clo,suspend)); + } catch (...) { + _suspended = SQTrue; + _suspended_target = ct_target; + _suspended_root = ci->_root; + _suspended_traps = traps; + _suspend_varargs = ci->_vargs; + throw; + } + if(suspend){ + _suspended = SQTrue; + _suspended_target = ct_target; + _suspended_root = ci->_root; + _suspended_traps = traps; + _suspend_varargs = ci->_vargs; + outres = clo; + return true; + } + if(ct_target != -1) { //skip return value for constructors + STK(ct_target) = clo; + } + } + continue; + case OT_CLASS:{ + SQObjectPtr inst; + _GUARD(CreateClassInstance(_class(clo),inst,temp_reg)); + STK(ct_target) = inst; + ct_target = -1; //fakes return value target so that is not overwritten by the constructor + if(type(temp_reg) != OT_NULL) { + _stack._vals[ct_stackbase] = inst; + goto common_call; //hard core spaghetti code(reissues the OP_CALL to invoke the constructor) + } + } + break; + case OT_TABLE: + case OT_USERDATA: + case OT_INSTANCE: + { + Push(clo); + for (SQInteger i = 0; i < arg3; i++) Push(STK(arg2 + i)); + if (_delegable(clo) && CallMetaMethod(_delegable(clo), MT_CALL, arg3+1, clo)){ + STK(ct_target) = clo; + break; + } + Raise_Error("attempt to call '%s'", GetTypeName(clo)); + SQ_THROW(); + } + default: + Raise_Error("attempt to call '%s'", GetTypeName(clo)); + SQ_THROW(); + } + } + continue; + case _OP_PREPCALL: + case _OP_PREPCALLK: + { + SQObjectPtr &key = _i_.op == _OP_PREPCALLK?(ci->_literals)[arg1]:STK(arg1); + SQObjectPtr &o = STK(arg2); + if (!Get(o, key, temp_reg,false,true)) { + if(type(o) == OT_CLASS) { //hack? + if(_class_ddel->Get(key,temp_reg)) { + STK(arg3) = o; + TARGET = temp_reg; + continue; + } + } + { Raise_IdxError(key); SQ_THROW();} + } + + STK(arg3) = type(o) == OT_CLASS?STK(0):o; + TARGET = temp_reg; + } + continue; + case _OP_SCOPE_END: + { + SQInteger from = arg0; + SQInteger count = arg1 - arg0 + 2; + /* When 'return' is executed, it happens that the stack is already cleaned + * (by Return()), but this OP-code is still executed. So check for this + * situation, and ignore the cleanup */ + if (_stackbase + count + from <= _top) { + while (--count >= 0) _stack._vals[_stackbase + count + from].Null(); + } + } continue; + case _OP_GETK: + if (!Get(STK(arg2), ci->_literals[arg1], temp_reg, false,true)) { Raise_IdxError(ci->_literals[arg1]); SQ_THROW();} + TARGET = temp_reg; + continue; + case _OP_MOVE: TARGET = STK(arg1); continue; + case _OP_NEWSLOT: + _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3),false)); + if(arg0 != arg3) TARGET = STK(arg3); + continue; + case _OP_DELETE: _GUARD(DeleteSlot(STK(arg1), STK(arg2), TARGET)); continue; + case _OP_SET: + if (!Set(STK(arg1), STK(arg2), STK(arg3),true)) { Raise_IdxError(STK(arg2)); SQ_THROW(); } + if (arg0 != arg3) TARGET = STK(arg3); + continue; + case _OP_GET: + if (!Get(STK(arg1), STK(arg2), temp_reg, false,true)) { Raise_IdxError(STK(arg2)); SQ_THROW(); } + TARGET = temp_reg; + continue; + case _OP_EQ:{ + bool res; + if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); } + TARGET = res?_true_:_false_; + }continue; + case _OP_NE:{ + bool res; + if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); } + TARGET = (!res)?_true_:_false_; + } continue; + case _OP_ARITH: _GUARD(ARITH_OP( arg3 , temp_reg, STK(arg2), STK(arg1))); TARGET = temp_reg; continue; + case _OP_BITW: _GUARD(BW_OP( arg3,TARGET,STK(arg2),STK(arg1))); continue; + case _OP_RETURN: + if(ci->_generator) { + ci->_generator->Kill(); + } + if(Return(arg0, arg1, temp_reg)){ + assert(traps==0); + outres = temp_reg; + return true; + } + continue; + case _OP_LOADNULLS:{ for(SQInt32 n=0; n < arg1; n++) STK(arg0+n) = _null_; }continue; + case _OP_LOADROOTTABLE: TARGET = _roottable; continue; + case _OP_LOADBOOL: TARGET = arg1?_true_:_false_; continue; + case _OP_DMOVE: STK(arg0) = STK(arg1); STK(arg2) = STK(arg3); continue; + case _OP_JMP: ci->_ip += (sarg1); continue; + case _OP_JNZ: if(!IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue; + case _OP_JZ: if(IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue; + case _OP_LOADFREEVAR: TARGET = _closure(ci->_closure)->_outervalues[arg1]; continue; + case _OP_VARGC: TARGET = SQInteger(ci->_vargs.size); continue; + case _OP_GETVARGV: + if(!GETVARGV_OP(TARGET,STK(arg1),ci)) { SQ_THROW(); } + continue; + case _OP_NEWTABLE: TARGET = SQTable::Create(_ss(this), arg1); continue; + case _OP_NEWARRAY: TARGET = SQArray::Create(_ss(this), 0); _array(TARGET)->Reserve(arg1); continue; + case _OP_APPENDARRAY: _array(STK(arg0))->Append(COND_LITERAL); continue; + case _OP_GETPARENT: _GUARD(GETPARENT_OP(STK(arg1),TARGET)); continue; + case _OP_COMPARITH: _GUARD(DerefInc(arg3, TARGET, STK((((SQUnsignedInteger)arg1&0xFFFF0000)>>16)), STK(arg2), STK(arg1&0x0000FFFF), false)); continue; + case _OP_COMPARITHL: _GUARD(LOCAL_INC(arg3, TARGET, STK(arg1), STK(arg2))); continue; + case _OP_INC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, false));} continue; + case _OP_INCL: {SQObjectPtr o(sarg3); _GUARD(LOCAL_INC('+',TARGET, STK(arg1), o));} continue; + case _OP_PINC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, true));} continue; + case _OP_PINCL: {SQObjectPtr o(sarg3); _GUARD(PLOCAL_INC('+',TARGET, STK(arg1), o));} continue; + case _OP_CMP: _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg1),TARGET)) continue; + case _OP_EXISTS: TARGET = Get(STK(arg1), STK(arg2), temp_reg, true,false)?_true_:_false_;continue; + case _OP_INSTANCEOF: + if(type(STK(arg1)) != OT_CLASS || type(STK(arg2)) != OT_INSTANCE) + {Raise_Error("cannot apply instanceof between a %s and a %s",GetTypeName(STK(arg1)),GetTypeName(STK(arg2))); SQ_THROW();} + TARGET = _instance(STK(arg2))->InstanceOf(_class(STK(arg1)))?_true_:_false_; + continue; + case _OP_AND: + if(IsFalse(STK(arg2))) { + TARGET = STK(arg2); + ci->_ip += (sarg1); + } + continue; + case _OP_OR: + if(!IsFalse(STK(arg2))) { + TARGET = STK(arg2); + ci->_ip += (sarg1); + } + continue; + case _OP_NEG: _GUARD(NEG_OP(TARGET,STK(arg1))); continue; + case _OP_NOT: TARGET = (IsFalse(STK(arg1))?_true_:_false_); continue; + case _OP_BWNOT: + if(type(STK(arg1)) == OT_INTEGER) { + SQInteger t = _integer(STK(arg1)); + TARGET = SQInteger(~t); + continue; + } + Raise_Error("attempt to perform a bitwise op on a %s", GetTypeName(STK(arg1))); + SQ_THROW(); + case _OP_CLOSURE: { + SQClosure *c = ci->_closure._unVal.pClosure; + SQFunctionProto *fp = c->_function._unVal.pFunctionProto; + if(!CLOSURE_OP(TARGET,fp->_functions[arg1]._unVal.pFunctionProto)) { SQ_THROW(); } + continue; + } + case _OP_YIELD:{ + if(ci->_generator) { + if(sarg1 != MAX_FUNC_STACKSIZE) temp_reg = STK(arg1); + _GUARD(ci->_generator->Yield(this)); + traps -= ci->_etraps; + if(sarg1 != MAX_FUNC_STACKSIZE) STK(arg1) = temp_reg; + } + else { Raise_Error("trying to yield a '%s',only genenerator can be yielded", GetTypeName(ci->_closure)); SQ_THROW();} + if(Return(arg0, arg1, temp_reg)){ + assert(traps == 0); + outres = temp_reg; + return true; + } + + } + continue; + case _OP_RESUME: + if(type(STK(arg1)) != OT_GENERATOR){ Raise_Error("trying to resume a '%s',only genenerator can be resumed", GetTypeName(STK(arg1))); SQ_THROW();} + _GUARD(_generator(STK(arg1))->Resume(this, arg0)); + traps += ci->_etraps; + continue; + case _OP_FOREACH:{ int tojump; + _GUARD(FOREACH_OP(STK(arg0),STK(arg2),STK(arg2+1),STK(arg2+2),arg2,sarg1,tojump)); + ci->_ip += tojump; } + continue; + case _OP_POSTFOREACH: + assert(type(STK(arg0)) == OT_GENERATOR); + if(_generator(STK(arg0))->_state == SQGenerator::eDead) + ci->_ip += (sarg1 - 1); + continue; + case _OP_DELEGATE: _GUARD(DELEGATE_OP(TARGET,STK(arg1),STK(arg2))); continue; + case _OP_CLONE: + if(!Clone(STK(arg1), TARGET)) + { Raise_Error("cloning a %s", GetTypeName(STK(arg1))); SQ_THROW();} + continue; + case _OP_TYPEOF: TypeOf(STK(arg1), TARGET); continue; + case _OP_PUSHTRAP:{ + SQInstruction *_iv = _funcproto(_closure(ci->_closure)->_function)->_instructions; + _etraps.push_back(SQExceptionTrap(_top,_stackbase, &_iv[(ci->_ip-_iv)+arg1], arg0)); traps++; + ci->_etraps++; + } + continue; + case _OP_POPTRAP: { + for(SQInteger i = 0; i < arg0; i++) { + _etraps.pop_back(); traps--; + ci->_etraps--; + } + } + continue; + case _OP_THROW: Raise_Error(TARGET); SQ_THROW(); + case _OP_CLASS: _GUARD(CLASS_OP(TARGET,arg1,arg2)); continue; + case _OP_NEWSLOTA: + bool bstatic = (arg0&NEW_SLOT_STATIC_FLAG)?true:false; + if(type(STK(arg1)) == OT_CLASS) { + if(type(_class(STK(arg1))->_metamethods[MT_NEWMEMBER]) != OT_NULL ) { + Push(STK(arg1)); Push(STK(arg2)); Push(STK(arg3)); + Push((arg0&NEW_SLOT_ATTRIBUTES_FLAG) ? STK(arg2-1) : _null_); + Push(bstatic); + int nparams = 5; + if(Call(_class(STK(arg1))->_metamethods[MT_NEWMEMBER], nparams, _top - nparams, temp_reg,SQFalse,SQFalse)) { + Pop(nparams); + continue; + } + } + } + _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3),bstatic)); + if((arg0&NEW_SLOT_ATTRIBUTES_FLAG)) { + _class(STK(arg1))->SetAttributes(STK(arg2),STK(arg2-1)); + } + continue; + } + + } + } +exception_trap: + { + SQObjectPtr currerror = _lasterror; +// dumpstack(_stackbase); + SQInteger n = 0; + SQInteger last_top = _top; + if(ci) { + if(_ss(this)->_notifyallexceptions) CallErrorHandler(currerror); + + if(traps) { + do { + if(ci->_etraps > 0) { + SQExceptionTrap &et = _etraps.top(); + ci->_ip = et._ip; + _top = et._stacksize; + _stackbase = et._stackbase; + _stack._vals[_stackbase+et._extarget] = currerror; + _etraps.pop_back(); traps--; ci->_etraps--; + CLEARSTACK(last_top); + goto exception_restore; + } + //if is a native closure + if(type(ci->_closure) != OT_CLOSURE && n) + break; + if(ci->_generator) ci->_generator->Kill(); + PopVarArgs(ci->_vargs); + POP_CALLINFO(this); + n++; + } while(_callsstacksize); + } + else { + //call the hook + if(raiseerror && !_ss(this)->_notifyallexceptions) + CallErrorHandler(currerror); + } + //remove call stack until a C function is found or the cstack is empty + if(ci) do { + SQBool exitafterthisone = ci->_root; + if(ci->_generator) ci->_generator->Kill(); + _stackbase -= ci->_prevstkbase; + _top = _stackbase + ci->_prevtop; + PopVarArgs(ci->_vargs); + POP_CALLINFO(this); + if( (ci && type(ci->_closure) != OT_CLOSURE) || exitafterthisone) break; + } while(_callsstacksize); + + CLEARSTACK(last_top); + } + _lasterror = currerror; + return false; + } + assert(0); +} + +bool SQVM::CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor) +{ + inst = theclass->CreateInstance(); + if(!theclass->Get(_ss(this)->_constructoridx,constructor)) { + constructor = _null_; + } + return true; +} + +void SQVM::CallErrorHandler(SQObjectPtr &error) +{ + if(type(_errorhandler) != OT_NULL) { + SQObjectPtr out; + Push(_roottable); Push(error); + Call(_errorhandler, 2, _top-2, out,SQFalse,SQFalse); + Pop(2); + } +} + +void SQVM::CallDebugHook(SQInteger type,SQInteger forcedline) +{ + SQObjectPtr temp_reg; + SQInteger nparams=5; + SQFunctionProto *func=_funcproto(_closure(ci->_closure)->_function); + Push(_roottable); Push(type); Push(func->_sourcename); Push(forcedline?forcedline:func->GetLine(ci->_ip)); Push(func->_name); + Call(_debughook,nparams,_top-nparams,temp_reg,SQFalse,SQFalse); + Pop(nparams); +} + +bool SQVM::CallNative(SQNativeClosure *nclosure,SQInteger nargs,SQInteger stackbase,SQObjectPtr &retval,bool &suspend) +{ + if (_nnativecalls + 1 > MAX_NATIVE_CALLS) { Raise_Error("Native stack overflow"); return false; } + SQInteger nparamscheck = nclosure->_nparamscheck; + if(((nparamscheck > 0) && (nparamscheck != nargs)) + || ((nparamscheck < 0) && (nargs < (-nparamscheck)))) { + Raise_Error("wrong number of parameters"); + return false; + } + + SQInteger tcs; + if((tcs = nclosure->_typecheck.size())) { + for(SQInteger i = 0; i < nargs && i < tcs; i++) + if((nclosure->_typecheck._vals[i] != -1) && !(type(_stack._vals[stackbase+i]) & nclosure->_typecheck[i])) { + Raise_ParamTypeError(i,nclosure->_typecheck._vals[i],type(_stack._vals[stackbase+i])); + return false; + } + } + _nnativecalls++; + if ((_top + MIN_STACK_OVERHEAD) > (SQInteger)_stack.size()) { + _stack.resize(_stack.size() + (MIN_STACK_OVERHEAD<<1)); + } + SQInteger oldtop = _top; + SQInteger oldstackbase = _stackbase; + _top = stackbase + nargs; + CallInfo lci; + memset(&lci, 0, sizeof(lci)); + lci._closure = nclosure; + lci._generator = NULL; + lci._etraps = 0; + lci._prevstkbase = (SQInt32) (stackbase - _stackbase); + lci._ncalls = 1; + lci._prevtop = (SQInt32) (oldtop - oldstackbase); + PUSH_CALLINFO(this, lci); + _stackbase = stackbase; + //push free variables + SQInteger outers = nclosure->_outervalues.size(); + for (SQInteger i = 0; i < outers; i++) { + Push(nclosure->_outervalues[i]); + } + + if(type(nclosure->_env) == OT_WEAKREF) { + _stack[stackbase] = _weakref(nclosure->_env)->_obj; + } + + + /* Store the call stack size, so we can restore that */ + SQInteger cstksize = _callsstacksize; + SQInteger ret; + try { + SQBool can_suspend = this->_can_suspend; + this->_can_suspend = false; + ret = (nclosure->_function)(this); + this->_can_suspend = can_suspend; + } catch (...) { + _nnativecalls--; + suspend = false; + + _callsstacksize = cstksize; + _stackbase = oldstackbase; + _top = oldtop; + + POP_CALLINFO(this); + + while(oldtop > _stackbase + stackbase) _stack._vals[oldtop--].Null(); + throw; + } + + _callsstacksize = cstksize; + + _nnativecalls--; + suspend = false; + if( ret == SQ_SUSPEND_FLAG) suspend = true; + else if (ret < 0) { + _stackbase = oldstackbase; + _top = oldtop; + POP_CALLINFO(this); + while(oldtop > _stackbase + stackbase) _stack._vals[oldtop--].Null(); + Raise_Error(_lasterror); + return false; + } + + if (ret != 0){ retval = TOP(); TOP().Null(); } + else { retval = _null_; } + _stackbase = oldstackbase; + _top = oldtop; + POP_CALLINFO(this); + while(oldtop > _stackbase + stackbase) _stack._vals[oldtop--].Null(); + return true; +} + +bool SQVM::Get(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw, bool fetchroot) +{ + switch(type(self)){ + case OT_TABLE: + if(_table(self)->Get(key,dest))return true; + break; + case OT_ARRAY: + if(sq_isnumeric(key)){ + return _array(self)->Get(tointeger(key),dest); + } + break; + case OT_INSTANCE: + if(_instance(self)->Get(key,dest)) return true; + break; + default:break; //shut up compiler + } + if(FallBackGet(self,key,dest,raw)) return true; + + if(fetchroot) { + if(_rawval(STK(0)) == _rawval(self) && + type(STK(0)) == type(self)) { + return _table(_roottable)->Get(key,dest); + } + } + return false; +} + +bool SQVM::FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw) +{ + switch(type(self)){ + case OT_CLASS: + return _class(self)->Get(key,dest); + break; + case OT_TABLE: + case OT_USERDATA: + //delegation + if(_delegable(self)->_delegate) { + if(Get(SQObjectPtr(_delegable(self)->_delegate),key,dest,raw,false)) + return true; + if(raw)return false; + Push(self);Push(key); + if(CallMetaMethod(_delegable(self),MT_GET,2,dest)) + return true; + } + if(type(self) == OT_TABLE) { + if(raw) return false; + return _table_ddel->Get(key,dest); + } + return false; + break; + case OT_ARRAY: + if(raw)return false; + return _array_ddel->Get(key,dest); + case OT_STRING: + if(sq_isnumeric(key)){ + SQInteger n=tointeger(key); + if(abs((int)n)<_string(self)->_len){ + if(n<0)n=_string(self)->_len-n; + dest=SQInteger(_stringval(self)[n]); + return true; + } + return false; + } + else { + if(raw)return false; + return _string_ddel->Get(key,dest); + } + break; + case OT_INSTANCE: + if(raw)return false; + Push(self);Push(key); + if(!CallMetaMethod(_delegable(self),MT_GET,2,dest)) { + return _instance_ddel->Get(key,dest); + } + return true; + case OT_INTEGER:case OT_FLOAT:case OT_BOOL: + if(raw)return false; + return _number_ddel->Get(key,dest); + case OT_GENERATOR: + if(raw)return false; + return _generator_ddel->Get(key,dest); + case OT_CLOSURE: case OT_NATIVECLOSURE: + if(raw)return false; + return _closure_ddel->Get(key,dest); + case OT_THREAD: + if(raw)return false; + return _thread_ddel->Get(key,dest); + case OT_WEAKREF: + if(raw)return false; + return _weakref_ddel->Get(key,dest); + default:return false; + } + return false; +} + +bool SQVM::Set(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,bool fetchroot) +{ + switch(type(self)){ + case OT_TABLE: + if(_table(self)->Set(key,val)) + return true; + if(_table(self)->_delegate) { + if(Set(_table(self)->_delegate,key,val,false)) { + return true; + } + } + //keeps going + case OT_USERDATA: + if(_delegable(self)->_delegate) { + SQObjectPtr t; + Push(self);Push(key);Push(val); + if(CallMetaMethod(_delegable(self),MT_SET,3,t)) return true; + } + break; + case OT_INSTANCE:{ + if(_instance(self)->Set(key,val)) + return true; + SQObjectPtr t; + Push(self);Push(key);Push(val); + if(CallMetaMethod(_delegable(self),MT_SET,3,t)) return true; + } + break; + case OT_ARRAY: + if(!sq_isnumeric(key)) {Raise_Error("indexing %s with %s",GetTypeName(self),GetTypeName(key)); return false; } + return _array(self)->Set(tointeger(key),val); + default: + Raise_Error("trying to set '%s'",GetTypeName(self)); + return false; + } + if(fetchroot) { + if(_rawval(STK(0)) == _rawval(self) && + type(STK(0)) == type(self)) { + return _table(_roottable)->Set(key,val); + } + } + return false; +} + +bool SQVM::Clone(const SQObjectPtr &self,SQObjectPtr &target) +{ + SQObjectPtr temp_reg; + SQObjectPtr newobj; + switch(type(self)){ + case OT_TABLE: + newobj = _table(self)->Clone(); + goto cloned_mt; + case OT_INSTANCE: + newobj = _instance(self)->Clone(_ss(this)); +cloned_mt: + if(_delegable(newobj)->_delegate){ + Push(newobj); + Push(self); + CallMetaMethod(_delegable(newobj),MT_CLONED,2,temp_reg); + } + target = newobj; + return true; + case OT_ARRAY: + target = _array(self)->Clone(); + return true; + default: return false; + } +} + +bool SQVM::NewSlot(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic) +{ + if(type(key) == OT_NULL) { Raise_Error("null cannot be used as index"); return false; } + switch(type(self)) { + case OT_TABLE: { + bool rawcall = true; + if(_table(self)->_delegate) { + SQObjectPtr res; + if(!_table(self)->Get(key,res)) { + Push(self);Push(key);Push(val); + rawcall = !CallMetaMethod(_table(self),MT_NEWSLOT,3,res); + } + } + if(rawcall) _table(self)->NewSlot(key,val); //cannot fail + + break;} + case OT_INSTANCE: { + SQObjectPtr res; + Push(self);Push(key);Push(val); + if(!CallMetaMethod(_instance(self),MT_NEWSLOT,3,res)) { + Raise_Error("class instances do not support the new slot operator"); + return false; + } + break;} + case OT_CLASS: + if(!_class(self)->NewSlot(_ss(this),key,val,bstatic)) { + if(_class(self)->_locked) { + Raise_Error("trying to modify a class that has already been instantiated"); + return false; + } + else { + SQObjectPtr oval = PrintObjVal(key); + Raise_Error("the property '%s' already exists",_stringval(oval)); + return false; + } + } + break; + default: + Raise_Error("indexing %s with %s",GetTypeName(self),GetTypeName(key)); + return false; + break; + } + return true; +} + +bool SQVM::DeleteSlot(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &res) +{ + switch(type(self)) { + case OT_TABLE: + case OT_INSTANCE: + case OT_USERDATA: { + SQObjectPtr t; + bool handled = false; + if(_delegable(self)->_delegate) { + Push(self);Push(key); + handled = CallMetaMethod(_delegable(self),MT_DELSLOT,2,t); + } + + if(!handled) { + if(type(self) == OT_TABLE) { + if(_table(self)->Get(key,t)) { + _table(self)->Remove(key); + } + else { + Raise_IdxError((const SQObject &)key); + return false; + } + } + else { + Raise_Error("cannot delete a slot from %s",GetTypeName(self)); + return false; + } + } + res = t; + } + break; + default: + Raise_Error("attempt to delete a slot from a %s",GetTypeName(self)); + return false; + } + return true; +} + +bool SQVM::Call(SQObjectPtr &closure,SQInteger nparams,SQInteger stackbase,SQObjectPtr &outres,SQBool raiseerror,SQBool can_suspend) +{ +#ifdef _DEBUG +SQInteger prevstackbase = _stackbase; +#endif + switch(type(closure)) { + case OT_CLOSURE: { + assert(!can_suspend || this->_can_suspend); + SQBool backup_suspend = this->_can_suspend; + this->_can_suspend = can_suspend; + bool ret = Execute(closure, _top - nparams, nparams, stackbase,outres,raiseerror); + this->_can_suspend = backup_suspend; + return ret; + } + break; + case OT_NATIVECLOSURE:{ + bool suspend; + return CallNative(_nativeclosure(closure), nparams, stackbase, outres,suspend); + + } + break; + case OT_CLASS: { + SQObjectPtr constr; + SQObjectPtr temp; + CreateClassInstance(_class(closure),outres,constr); + if(type(constr) != OT_NULL) { + _stack[stackbase] = outres; + return Call(constr,nparams,stackbase,temp,raiseerror,false); + } + return true; + } + break; + default: + return false; + } +#ifdef _DEBUG + if(!_suspended) { + assert(_stackbase == prevstackbase); + } +#endif + return true; +} + +bool SQVM::CallMetaMethod(SQDelegable *del,SQMetaMethod mm,SQInteger nparams,SQObjectPtr &outres) +{ + SQObjectPtr closure; + if(del->GetMetaMethod(this, mm, closure)) { + if(Call(closure, nparams, _top - nparams, outres, SQFalse, SQFalse)) { + Pop(nparams); + return true; + } + } + Pop(nparams); + return false; +} + +void SQVM::Remove(SQInteger n) { + n = (n >= 0)?n + _stackbase - 1:_top + n; + for(SQInteger i = n; i < _top; i++){ + _stack[i] = _stack[i+1]; + } + _stack[_top] = _null_; + _top--; +} + +void SQVM::Pop() { + _stack[--_top] = _null_; +} + +void SQVM::Pop(SQInteger n) { + for(SQInteger i = 0; i < n; i++){ + _stack[--_top] = _null_; + } +} + +void SQVM::Push(const SQObjectPtr &o) { + /* Normally the stack shouldn't get this full, sometimes it might. As of now + * all cases have been bugs in "our" (OpenTTD) code. Trigger an assert for + * all debug builds and for the release builds just increase the stack size. + * This way getting a false positive isn't that bad (releases work fine) and + * if there is something fishy it can be caught in RCs/nightlies. */ +#ifdef NDEBUG + if (_top >= (int)_stack.capacity()) _stack.resize(2 * _stack.capacity()); +#else + assert(_top < (int)_stack.capacity()); +#endif + _stack[_top++] = o; +} +SQObjectPtr &SQVM::Top() { return _stack[_top-1]; } +SQObjectPtr &SQVM::PopGet() { return _stack[--_top]; } +SQObjectPtr &SQVM::GetUp(SQInteger n) { return _stack[_top+n]; } +SQObjectPtr &SQVM::GetAt(SQInteger n) { return _stack[n]; } + +#ifdef _DEBUG_DUMP +void SQVM::dumpstack(SQInteger stackbase,bool dumpall) +{ + SQInteger size=dumpall?_stack.size():_top; + SQInteger n=0; + printf("\n>>>>stack dump<<<<\n"); + CallInfo &ci=_callsstack[_callsstacksize-1]; + printf("IP: %p\n",ci._ip); + printf("prev stack base: %d\n",ci._prevstkbase); + printf("prev top: %d\n",ci._prevtop); + for(SQInteger i=0;i");else printf(" "); + printf("[%d]:",n); + switch(type(obj)){ + case OT_FLOAT: printf("FLOAT %.3f",_float(obj));break; + case OT_INTEGER: printf("INTEGER %d",_integer(obj));break; + case OT_BOOL: printf("BOOL %s",_integer(obj)?"true":"false");break; + case OT_STRING: printf("STRING %s",_stringval(obj));break; + case OT_NULL: printf("NULL"); break; + case OT_TABLE: printf("TABLE %p[%p]",_table(obj),_table(obj)->_delegate);break; + case OT_ARRAY: printf("ARRAY %p",_array(obj));break; + case OT_CLOSURE: printf("CLOSURE [%p]",_closure(obj));break; + case OT_NATIVECLOSURE: printf("NATIVECLOSURE");break; + case OT_USERDATA: printf("USERDATA %p[%p]",_userdataval(obj),_userdata(obj)->_delegate);break; + case OT_GENERATOR: printf("GENERATOR %p",_generator(obj));break; + case OT_THREAD: printf("THREAD [%p]",_thread(obj));break; + case OT_USERPOINTER: printf("USERPOINTER %p",_userpointer(obj));break; + case OT_CLASS: printf("CLASS %p",_class(obj));break; + case OT_INSTANCE: printf("INSTANCE %p",_instance(obj));break; + case OT_WEAKREF: printf("WEAKERF %p",_weakref(obj));break; + default: + assert(0); + break; + }; + printf("\n"); + ++n; + } +} + + + +#endif diff --git a/src/3rdparty/squirrel/squirrel/sqvm.h b/src/3rdparty/squirrel/squirrel/sqvm.h new file mode 100644 index 0000000..89a592e --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqvm.h @@ -0,0 +1,225 @@ +/* see copyright notice in squirrel.h */ +#ifndef _SQVM_H_ +#define _SQVM_H_ + +#include "sqopcodes.h" +#include "sqobject.h" +#define MAX_NATIVE_CALLS 100 +#define MIN_STACK_OVERHEAD 10 + +#define SQ_SUSPEND_FLAG -666 +//base lib +void sq_base_register(HSQUIRRELVM v); + +struct SQExceptionTrap{ + SQExceptionTrap() {} + SQExceptionTrap(SQInteger ss, SQInteger stackbase,SQInstruction *ip, SQInteger ex_target){ _stacksize = ss; _stackbase = stackbase; _ip = ip; _extarget = ex_target;} + SQExceptionTrap(const SQExceptionTrap &et) { (*this) = et; } + SQInteger _stackbase; + SQInteger _stacksize; + SQInstruction *_ip; + SQInteger _extarget; +}; + +#define _INLINE + +#define STK(a) _stack._vals[_stackbase+(a)] +#define TARGET _stack._vals[_stackbase+arg0] + +typedef sqvector ExceptionsTraps; + +struct SQVM : public CHAINABLE_OBJ +{ + struct VarArgs { + VarArgs() { size = 0; base = 0; } + unsigned short size; + unsigned short base; + }; + + struct CallInfo{ + //CallInfo() { _generator._type = OT_NULL;} + SQInstruction *_ip; + SQObjectPtr *_literals; + SQObjectPtr _closure; + SQGenerator *_generator; + SQInt32 _etraps; + SQInt32 _prevstkbase; + SQInt32 _prevtop; + SQInt32 _target; + SQInt32 _ncalls; + SQBool _root; + VarArgs _vargs; + }; + +typedef sqvector CallInfoVec; +public: + enum ExecutionType { ET_CALL, ET_RESUME_GENERATOR, ET_RESUME_VM, ET_RESUME_THROW_VM, ET_RESUME_OPENTTD }; + SQVM(SQSharedState *ss); + ~SQVM(); + bool Init(SQVM *friendvm, SQInteger stacksize); + bool Execute(SQObjectPtr &func, SQInteger target, SQInteger nargs, SQInteger stackbase, SQObjectPtr &outres, SQBool raiseerror, ExecutionType et = ET_CALL); + //starts a native call return when the NATIVE closure returns + bool CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger stackbase, SQObjectPtr &retval,bool &suspend); + //starts a SQUIRREL call in the same "Execution loop" + bool StartCall(SQClosure *closure, SQInteger target, SQInteger nargs, SQInteger stackbase, bool tailcall); + bool CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor); + //call a generic closure pure SQUIRREL or NATIVE + bool Call(SQObjectPtr &closure, SQInteger nparams, SQInteger stackbase, SQObjectPtr &outres,SQBool raiseerror,SQBool can_suspend); + SQRESULT Suspend(); + + void CallDebugHook(SQInteger type,SQInteger forcedline=0); + void CallErrorHandler(SQObjectPtr &e); + bool Get(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, bool raw, bool fetchroot); + bool FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw); + bool Set(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val, bool fetchroot); + bool NewSlot(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val,bool bstatic); + bool DeleteSlot(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &res); + bool Clone(const SQObjectPtr &self, SQObjectPtr &target); + bool ObjCmp(const SQObjectPtr &o1, const SQObjectPtr &o2,SQInteger &res); + bool StringCat(const SQObjectPtr &str, const SQObjectPtr &obj, SQObjectPtr &dest); + bool IsEqual(SQObjectPtr &o1,SQObjectPtr &o2,bool &res); + void ToString(const SQObjectPtr &o,SQObjectPtr &res); + SQString *PrintObjVal(const SQObject &o); + + + void Raise_Error(const SQChar *s, ...); + void Raise_Error(SQObjectPtr &desc); + void Raise_IdxError(const SQObject &o); + void Raise_CompareError(const SQObject &o1, const SQObject &o2); + void Raise_ParamTypeError(SQInteger nparam,SQInteger typemask,SQInteger type); + + void TypeOf(const SQObjectPtr &obj1, SQObjectPtr &dest); + bool CallMetaMethod(SQDelegable *del, SQMetaMethod mm, SQInteger nparams, SQObjectPtr &outres); + bool ArithMetaMethod(SQInteger op, const SQObjectPtr &o1, const SQObjectPtr &o2, SQObjectPtr &dest); + bool Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval); + //new stuff + _INLINE bool ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2); + _INLINE bool BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2); + _INLINE bool NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o1); + _INLINE bool CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res); + bool CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func); + bool GETVARGV_OP(SQObjectPtr &target,SQObjectPtr &idx,CallInfo *ci); + bool CLASS_OP(SQObjectPtr &target,SQInteger base,SQInteger attrs); + bool GETPARENT_OP(SQObjectPtr &o,SQObjectPtr &target); + //return true if the loop is finished + bool FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr &o3,SQObjectPtr &o4,SQInteger arg_2,int exitpos,int &jump); + bool DELEGATE_OP(SQObjectPtr &trg,SQObjectPtr &o1,SQObjectPtr &o2); + _INLINE bool LOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr); + _INLINE bool PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr); + _INLINE bool DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix); + void PopVarArgs(VarArgs &vargs); + void ClearStack(SQInteger last_top); +#ifdef _DEBUG_DUMP + void dumpstack(SQInteger stackbase=-1, bool dumpall = false); +#endif + +#ifndef NO_GARBAGE_COLLECTOR + void Mark(SQCollectable **chain); +#endif + void Finalize(); + void GrowCallStack() { + SQInteger newsize = _alloccallsstacksize*2; + _callstackdata.resize(newsize); + _callsstack = &_callstackdata[0]; + _alloccallsstacksize = newsize; + } + void Release(){ sq_delete(this,SQVM); } //does nothing +//////////////////////////////////////////////////////////////////////////// + //stack functions for the api + void Remove(SQInteger n); + + bool IsFalse(SQObjectPtr &o); + + void Pop(); + void Pop(SQInteger n); + void Push(const SQObjectPtr &o); + SQObjectPtr &Top(); + SQObjectPtr &PopGet(); + SQObjectPtr &GetUp(SQInteger n); + SQObjectPtr &GetAt(SQInteger n); + + SQObjectPtrVec _stack; + SQObjectPtrVec _vargsstack; + SQInteger _top; + SQInteger _stackbase; + SQObjectPtr _roottable; + SQObjectPtr _lasterror; + SQObjectPtr _errorhandler; + SQObjectPtr _debughook; + + SQObjectPtr temp_reg; + + + CallInfo* _callsstack; + SQInteger _callsstacksize; + SQInteger _alloccallsstacksize; + sqvector _callstackdata; + + ExceptionsTraps _etraps; + CallInfo *ci; + void *_foreignptr; + //VMs sharing the same state + SQSharedState *_sharedstate; + SQInteger _nnativecalls; + //suspend infos + SQBool _suspended; + SQBool _suspended_root; + SQInteger _suspended_target; + SQInteger _suspended_traps; + VarArgs _suspend_varargs; + + SQBool _can_suspend; + SQInteger _ops_till_suspend; + SQBool _in_stackoverflow; + + bool ShouldSuspend() + { + return _can_suspend && _ops_till_suspend <= 0; + } + + void DecreaseOps(SQInteger amount) + { + if (_ops_till_suspend - amount < _ops_till_suspend) _ops_till_suspend -= amount; + } +}; + +struct AutoDec{ + AutoDec(SQInteger *n) { _n = n; } + ~AutoDec() { (*_n)--; } + SQInteger *_n; +}; + +inline SQObjectPtr &stack_get(HSQUIRRELVM v,SQInteger idx){return ((idx>=0)?(v->GetAt(idx+v->_stackbase-1)):(v->GetUp(idx)));} + +#define _ss(_vm_) (_vm_)->_sharedstate + +#ifndef NO_GARBAGE_COLLECTOR +#define _opt_ss(_vm_) (_vm_)->_sharedstate +#else +#define _opt_ss(_vm_) NULL +#endif + +#define PUSH_CALLINFO(v,nci){ \ + if(v->_callsstacksize == v->_alloccallsstacksize) { \ + if (v->_callsstacksize > 65535 && !v->_in_stackoverflow) {\ + v->_in_stackoverflow = true; \ + v->Raise_Error("stack overflow");\ + v->CallErrorHandler(v->_lasterror);\ + return false;\ + }\ + v->GrowCallStack(); \ + } \ + v->ci = &v->_callsstack[v->_callsstacksize]; \ + *(v->ci) = nci; \ + v->_callsstacksize++; \ +} + +#define POP_CALLINFO(v){ \ + v->_callsstacksize--; \ + v->ci->_closure.Null(); \ + if(v->_callsstacksize) \ + v->ci = &v->_callsstack[v->_callsstacksize-1] ; \ + else \ + v->ci = NULL; \ +} +#endif //_SQVM_H_ diff --git a/src/ai/ai.hpp b/src/ai/ai.hpp new file mode 100644 index 0000000..065367d --- /dev/null +++ b/src/ai/ai.hpp @@ -0,0 +1,178 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file ai.hpp Base functions for all AIs. */ + +#ifndef AI_HPP +#define AI_HPP + +#include "../script/api/script_event_types.hpp" +#include "../core/string_compare_type.hpp" +#include "ai_scanner.hpp" +#include + +/** A list that maps AI names to their AIInfo object. */ +typedef std::map ScriptInfoList; + +/** + * Main AI class. Contains all functions needed to start, stop, save and load AIs. + */ +class AI { +public: + /** + * The default months AIs start after each other. + */ + enum StartNext { + START_NEXT_EASY = DAYS_IN_YEAR * 2, + START_NEXT_MEDIUM = DAYS_IN_YEAR, + START_NEXT_HARD = DAYS_IN_YEAR / 2, + START_NEXT_MIN = 1, + START_NEXT_MAX = 3600, + START_NEXT_DEVIATION = 60, + }; + + /** + * Is it possible to start a new AI company? + * @return True if a new AI company can be started. + */ + static bool CanStartNew(); + + /** + * Start a new AI company. + * @param company At which slot the AI company should start. + * @param rerandomise_ai Whether to rerandomise the configured AI. + */ + static void StartNew(CompanyID company, bool rerandomise_ai = true); + + /** + * Called every game-tick to let AIs do something. + */ + static void GameLoop(); + + /** + * Get the current AI tick. + */ + static uint GetTick(); + + /** + * Stop a company to be controlled by an AI. + * @param company The company from which the AI needs to detach. + * @pre Company::IsValidAiID(company) + */ + static void Stop(CompanyID company); + + /** + * Suspend the AI and then pause execution of the script. The script + * will not be resumed from its suspended state until the script has + * been unpaused. + * @param company The company for which the AI should be paused. + * @pre Company::IsValidAiID(company) + */ + static void Pause(CompanyID company); + + /** + * Resume execution of the AI. This function will not actually execute + * the script, but set a flag so that the script is executed my the usual + * mechanism that executes the script. + * @param company The company for which the AI should be unpaused. + * @pre Company::IsValidAiID(company) + */ + static void Unpause(CompanyID company); + + /** + * Checks if the AI is paused. + * @param company The company for which to check if the AI is paused. + * @pre Company::IsValidAiID(company) + * @return true if the AI is paused, otherwise false. + */ + static bool IsPaused(CompanyID company); + + /** + * Kill any and all AIs we manage. + */ + static void KillAll(); + + /** + * Initialize the AI system. + */ + static void Initialize(); + + /** + * Uninitialize the AI system + * @param keepConfig Should we keep AIConfigs, or can we free that memory? + */ + static void Uninitialize(bool keepConfig); + + /** + * Reset all AIConfigs, and make them reload their AIInfo. + * If the AIInfo could no longer be found, an error is reported to the user. + */ + static void ResetConfig(); + + /** + * Queue a new event for an AI. + */ + static void NewEvent(CompanyID company, ScriptEvent *event); + + /** + * Broadcast a new event to all active AIs. + */ + static void BroadcastNewEvent(ScriptEvent *event, CompanyID skip_company = MAX_COMPANIES); + + /** + * Save data from an AI to a savegame. + */ + static void Save(CompanyID company); + + /** + * Load data for an AI from a savegame. + */ + static void Load(CompanyID company, int version); + + /** + * Get the number of days before the next AI should start. + */ + static int GetStartNextTime(); + + /** Wrapper function for AIScanner::GetAIConsoleList */ + static char *GetConsoleList(char *p, const char *last, bool newest_only = false); + /** Wrapper function for AIScanner::GetAIConsoleLibraryList */ + static char *GetConsoleLibraryList(char *p, const char *last); + /** Wrapper function for AIScanner::GetAIInfoList */ + static const ScriptInfoList *GetInfoList(); + /** Wrapper function for AIScanner::GetUniqueAIInfoList */ + static const ScriptInfoList *GetUniqueInfoList(); + /** Wrapper function for AIScanner::FindInfo */ + static class AIInfo *FindInfo(const char *name, int version, bool force_exact_match); + /** Wrapper function for AIScanner::FindLibrary */ + static class AILibrary *FindLibrary(const char *library, int version); + + /** + * Rescans all searchpaths for available AIs. If a used AI is no longer + * found it is removed from the config. + */ + static void Rescan(); + + /** Gets the ScriptScanner instance that is used to find AIs */ + static AIScannerInfo *GetScannerInfo(); + /** Gets the ScriptScanner instance that is used to find AI Libraries */ + static AIScannerLibrary *GetScannerLibrary(); + +#if defined(ENABLE_NETWORK) + /** Wrapper function for AIScanner::HasAI */ + static bool HasAI(const struct ContentInfo *ci, bool md5sum); + static bool HasAILibrary(const ContentInfo *ci, bool md5sum); +#endif +private: + static uint frame_counter; ///< Tick counter for the AI code + static class AIScannerInfo *scanner_info; ///< ScriptScanner instance that is used to find AIs + static class AIScannerLibrary *scanner_library; ///< ScriptScanner instance that is used to find AI Libraries +}; + +#endif /* AI_HPP */ diff --git a/src/ai/ai_config.cpp b/src/ai/ai_config.cpp new file mode 100644 index 0000000..f920d31 --- /dev/null +++ b/src/ai/ai_config.cpp @@ -0,0 +1,120 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file ai_config.cpp Implementation of AIConfig. */ + +#include "../stdafx.h" +#include "../settings_type.h" +#include "../string_func.h" +#include "ai.hpp" +#include "ai_config.hpp" +#include "ai_info.hpp" + +#include "../safeguards.h" + +/** Configuration for AI start date, every AI has this setting. */ +ScriptConfigItem _start_date_config = { + "start_date", + "", // STR_AI_SETTINGS_START_DELAY + AI::START_NEXT_MIN, + AI::START_NEXT_MAX, + AI::START_NEXT_MEDIUM, + AI::START_NEXT_EASY, + AI::START_NEXT_MEDIUM, + AI::START_NEXT_HARD, + AI::START_NEXT_DEVIATION, + 30, + SCRIPTCONFIG_NONE, + NULL, + false +}; + +/* static */ AIConfig *AIConfig::GetConfig(CompanyID company, ScriptSettingSource source) +{ + AIConfig **config; + if (source == SSS_FORCE_NEWGAME || (source == SSS_DEFAULT && _game_mode == GM_MENU)) { + config = &_settings_newgame.ai_config[company]; + } else { + config = &_settings_game.ai_config[company]; + } + if (*config == NULL) *config = new AIConfig(); + return *config; +} + +class AIInfo *AIConfig::GetInfo() const +{ + return static_cast(ScriptConfig::GetInfo()); +} + +ScriptInfo *AIConfig::FindInfo(const char *name, int version, bool force_exact_match) +{ + return static_cast(AI::FindInfo(name, version, force_exact_match)); +} + +bool AIConfig::ResetInfo(bool force_exact_match) +{ + this->info = (ScriptInfo *)AI::FindInfo(this->name, force_exact_match ? this->version : -1, force_exact_match); + return this->info != NULL; +} + +void AIConfig::PushExtraConfigList() +{ + this->config_list->push_back(_start_date_config); +} + +void AIConfig::ClearConfigList() +{ + /* The special casing for start_date is here to ensure that the + * start_date setting won't change even if you chose another Script. */ + int start_date = this->GetSetting("start_date"); + + ScriptConfig::ClearConfigList(); + + this->SetSetting("start_date", start_date); +} + +int AIConfig::GetSetting(const char *name) const +{ + if (this->info == NULL) { + SettingValueList::const_iterator it = this->settings.find(name); + if (it == this->settings.end()) { + assert(strcmp("start_date", name) == 0); + switch (GetGameSettings().script.settings_profile) { + case SP_EASY: return AI::START_NEXT_EASY; + case SP_MEDIUM: return AI::START_NEXT_MEDIUM; + case SP_HARD: return AI::START_NEXT_HARD; + case SP_CUSTOM: return AI::START_NEXT_MEDIUM; + default: NOT_REACHED(); + } + } + + return (*it).second; + } + + return ScriptConfig::GetSetting(name); +} + +void AIConfig::SetSetting(const char *name, int value) +{ + if (this->info == NULL) { + if (strcmp("start_date", name) != 0) return; + value = Clamp(value, AI::START_NEXT_MIN, AI::START_NEXT_MAX); + + SettingValueList::iterator it = this->settings.find(name); + if (it != this->settings.end()) { + (*it).second = value; + } else { + this->settings[stredup(name)] = value; + } + + return; + } + + ScriptConfig::SetSetting(name, value); +} diff --git a/src/ai/ai_config.hpp b/src/ai/ai_config.hpp new file mode 100644 index 0000000..b029359 --- /dev/null +++ b/src/ai/ai_config.hpp @@ -0,0 +1,54 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file ai_config.hpp AIConfig stores the configuration settings of every AI. */ + +#ifndef AI_CONFIG_HPP +#define AI_CONFIG_HPP + +#include "../script/script_config.hpp" +#include "../company_type.h" + +class AIConfig : public ScriptConfig { +public: + /** + * Get the config of a company. + */ + static AIConfig *GetConfig(CompanyID company, ScriptSettingSource source = SSS_DEFAULT); + + AIConfig() : + ScriptConfig() + {} + + AIConfig(const AIConfig *config) : + ScriptConfig(config) + {} + + class AIInfo *GetInfo() const; + + /* virtual */ int GetSetting(const char *name) const; + /* virtual */ void SetSetting(const char *name, int value); + + /** + * When ever the AI Scanner is reloaded, all infos become invalid. This + * function tells AIConfig about this. + * @param force_exact_match If true try to find the exact same version + * as specified. If false any version is ok. + * @return \c true if the reset was successful, \c false if the AI was no longer + * found. + */ + bool ResetInfo(bool force_exact_match); + +protected: + /* virtual */ void PushExtraConfigList(); + /* virtual */ void ClearConfigList(); + /* virtual */ ScriptInfo *FindInfo(const char *name, int version, bool force_exact_match); +}; + +#endif /* AI_CONFIG_HPP */ diff --git a/src/ai/ai_core.cpp b/src/ai/ai_core.cpp new file mode 100644 index 0000000..d4ff233 --- /dev/null +++ b/src/ai/ai_core.cpp @@ -0,0 +1,389 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file ai_core.cpp Implementation of AI. */ + +#include "../stdafx.h" +#include "../core/backup_type.hpp" +#include "../core/bitmath_func.hpp" +#include "../company_base.h" +#include "../company_func.h" +#include "../network/network.h" +#include "../window_func.h" +#include "ai_scanner.hpp" +#include "ai_instance.hpp" +#include "ai_config.hpp" +#include "ai_info.hpp" +#include "ai.hpp" + +#include "../safeguards.h" + +/* static */ uint AI::frame_counter = 0; +/* static */ AIScannerInfo *AI::scanner_info = NULL; +/* static */ AIScannerLibrary *AI::scanner_library = NULL; + +/* static */ bool AI::CanStartNew() +{ + /* Only allow new AIs on the server and only when that is allowed in multiplayer */ + return !_networking || (_network_server && _settings_game.ai.ai_in_multiplayer); +} + +/* static */ void AI::StartNew(CompanyID company, bool rerandomise_ai) +{ + assert(Company::IsValidID(company)); + + /* Clients shouldn't start AIs */ + if (_networking && !_network_server) return; + + AIConfig *config = AIConfig::GetConfig(company, AIConfig::SSS_FORCE_GAME); + AIInfo *info = config->GetInfo(); + if (info == NULL || (rerandomise_ai && config->IsRandom())) { + info = AI::scanner_info->SelectRandomAI(); + assert(info != NULL); + /* Load default data and store the name in the settings */ + config->Change(info->GetName(), -1, false, true); + } + config->AnchorUnchangeableSettings(); + + Backup cur_company(_current_company, company, FILE_LINE); + Company *c = Company::Get(company); + + c->ai_info = info; + assert(c->ai_instance == NULL); + c->ai_instance = new AIInstance(); + c->ai_instance->Initialize(info); + + cur_company.Restore(); + + InvalidateWindowData(WC_AI_DEBUG, 0, -1); + return; +} + +/* static */ void AI::GameLoop() +{ + /* If we are in networking, only servers run this function, and that only if it is allowed */ + if (_networking && (!_network_server || !_settings_game.ai.ai_in_multiplayer)) return; + + /* The speed with which AIs go, is limited by the 'competitor_speed' */ + AI::frame_counter++; + assert(_settings_game.difficulty.competitor_speed <= 4); + if ((AI::frame_counter & ((1 << (4 - _settings_game.difficulty.competitor_speed)) - 1)) != 0) return; + + Backup cur_company(_current_company, FILE_LINE); + const Company *c; + FOR_ALL_COMPANIES(c) { + if (c->is_ai) { + cur_company.Change(c->index); + c->ai_instance->GameLoop(); + } + } + cur_company.Restore(); + + /* Occasionally collect garbage; every 255 ticks do one company. + * Effectively collecting garbage once every two months per AI. */ + if ((AI::frame_counter & 255) == 0) { + CompanyID cid = (CompanyID)GB(AI::frame_counter, 8, 4); + if (Company::IsValidAiID(cid)) Company::Get(cid)->ai_instance->CollectGarbage(); + } +} + +/* static */ uint AI::GetTick() +{ + return AI::frame_counter; +} + +/* static */ void AI::Stop(CompanyID company) +{ + if (_networking && !_network_server) return; + + Backup cur_company(_current_company, company, FILE_LINE); + Company *c = Company::Get(company); + + delete c->ai_instance; + c->ai_instance = NULL; + c->ai_info = NULL; + + cur_company.Restore(); + + InvalidateWindowData(WC_AI_DEBUG, 0, -1); + DeleteWindowById(WC_AI_SETTINGS, company); +} + +/* static */ void AI::Pause(CompanyID company) +{ + /* The reason why dedicated servers are forbidden to execute this + * command is not because it is unsafe, but because there is no way + * for the server owner to unpause the script again. */ + if (_network_dedicated) return; + + Backup cur_company(_current_company, company, FILE_LINE); + Company::Get(company)->ai_instance->Pause(); + + cur_company.Restore(); +} + +/* static */ void AI::Unpause(CompanyID company) +{ + Backup cur_company(_current_company, company, FILE_LINE); + Company::Get(company)->ai_instance->Unpause(); + + cur_company.Restore(); +} + +/* static */ bool AI::IsPaused(CompanyID company) +{ + Backup cur_company(_current_company, company, FILE_LINE); + bool paused = Company::Get(company)->ai_instance->IsPaused(); + + cur_company.Restore(); + + return paused; +} + +/* static */ void AI::KillAll() +{ + /* It might happen there are no companies .. than we have nothing to loop */ + if (Company::GetPoolSize() == 0) return; + + const Company *c; + FOR_ALL_COMPANIES(c) { + if (c->is_ai) AI::Stop(c->index); + } +} + +/* static */ void AI::Initialize() +{ + if (AI::scanner_info != NULL) AI::Uninitialize(true); + + AI::frame_counter = 0; + if (AI::scanner_info == NULL) { + TarScanner::DoScan(TarScanner::AI); + AI::scanner_info = new AIScannerInfo(); + AI::scanner_info->Initialize(); + AI::scanner_library = new AIScannerLibrary(); + AI::scanner_library->Initialize(); + } +} + +/* static */ void AI::Uninitialize(bool keepConfig) +{ + AI::KillAll(); + + if (keepConfig) { + /* Run a rescan, which indexes all AIInfos again, and check if we can + * still load all the AIS, while keeping the configs in place */ + Rescan(); + } else { + delete AI::scanner_info; + delete AI::scanner_library; + AI::scanner_info = NULL; + AI::scanner_library = NULL; + + for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { + if (_settings_game.ai_config[c] != NULL) { + delete _settings_game.ai_config[c]; + _settings_game.ai_config[c] = NULL; + } + if (_settings_newgame.ai_config[c] != NULL) { + delete _settings_newgame.ai_config[c]; + _settings_newgame.ai_config[c] = NULL; + } + } + } +} + +/* static */ void AI::ResetConfig() +{ + /* Check for both newgame as current game if we can reload the AIInfo inside + * the AIConfig. If not, remove the AI from the list (which will assign + * a random new AI on reload). */ + for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { + if (_settings_game.ai_config[c] != NULL && _settings_game.ai_config[c]->HasScript()) { + if (!_settings_game.ai_config[c]->ResetInfo(true)) { + DEBUG(script, 0, "After a reload, the AI by the name '%s' was no longer found, and removed from the list.", _settings_game.ai_config[c]->GetName()); + _settings_game.ai_config[c]->Change(NULL); + if (Company::IsValidAiID(c)) { + /* The code belonging to an already running AI was deleted. We can only do + * one thing here to keep everything sane and that is kill the AI. After + * killing the offending AI we start a random other one in it's place, just + * like what would happen if the AI was missing during loading. */ + AI::Stop(c); + AI::StartNew(c, false); + } + } else if (Company::IsValidAiID(c)) { + /* Update the reference in the Company struct. */ + Company::Get(c)->ai_info = _settings_game.ai_config[c]->GetInfo(); + } + } + if (_settings_newgame.ai_config[c] != NULL && _settings_newgame.ai_config[c]->HasScript()) { + if (!_settings_newgame.ai_config[c]->ResetInfo(false)) { + DEBUG(script, 0, "After a reload, the AI by the name '%s' was no longer found, and removed from the list.", _settings_newgame.ai_config[c]->GetName()); + _settings_newgame.ai_config[c]->Change(NULL); + } + } + } +} + +/* static */ void AI::NewEvent(CompanyID company, ScriptEvent *event) +{ + /* AddRef() and Release() need to be called at least once, so do it here */ + event->AddRef(); + + /* Clients should ignore events */ + if (_networking && !_network_server) { + event->Release(); + return; + } + + /* Only AIs can have an event-queue */ + if (!Company::IsValidAiID(company)) { + event->Release(); + return; + } + + /* Queue the event */ + Backup cur_company(_current_company, company, FILE_LINE); + Company::Get(_current_company)->ai_instance->InsertEvent(event); + cur_company.Restore(); + + event->Release(); +} + +/* static */ void AI::BroadcastNewEvent(ScriptEvent *event, CompanyID skip_company) +{ + /* AddRef() and Release() need to be called at least once, so do it here */ + event->AddRef(); + + /* Clients should ignore events */ + if (_networking && !_network_server) { + event->Release(); + return; + } + + /* Try to send the event to all AIs */ + for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { + if (c != skip_company) AI::NewEvent(c, event); + } + + event->Release(); +} + +/* static */ void AI::Save(CompanyID company) +{ + if (!_networking || _network_server) { + Company *c = Company::GetIfValid(company); + assert(c != NULL && c->ai_instance != NULL); + + Backup cur_company(_current_company, company, FILE_LINE); + c->ai_instance->Save(); + cur_company.Restore(); + } else { + AIInstance::SaveEmpty(); + } +} + +/* static */ void AI::Load(CompanyID company, int version) +{ + if (!_networking || _network_server) { + Company *c = Company::GetIfValid(company); + assert(c != NULL && c->ai_instance != NULL); + + Backup cur_company(_current_company, company, FILE_LINE); + c->ai_instance->Load(version); + cur_company.Restore(); + } else { + /* Read, but ignore, the load data */ + AIInstance::LoadEmpty(); + } +} + +/* static */ int AI::GetStartNextTime() +{ + /* Find the first company which doesn't exist yet */ + for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { + if (!Company::IsValidID(c)) return AIConfig::GetConfig(c, AIConfig::SSS_FORCE_GAME)->GetSetting("start_date"); + } + + /* Currently no AI can be started, check again in a year. */ + return DAYS_IN_YEAR; +} + +/* static */ char *AI::GetConsoleList(char *p, const char *last, bool newest_only) +{ + return AI::scanner_info->GetConsoleList(p, last, newest_only); +} + +/* static */ char *AI::GetConsoleLibraryList(char *p, const char *last) +{ + return AI::scanner_library->GetConsoleList(p, last, true); +} + +/* static */ const ScriptInfoList *AI::GetInfoList() +{ + return AI::scanner_info->GetInfoList(); +} + +/* static */ const ScriptInfoList *AI::GetUniqueInfoList() +{ + return AI::scanner_info->GetUniqueInfoList(); +} + +/* static */ AIInfo *AI::FindInfo(const char *name, int version, bool force_exact_match) +{ + return AI::scanner_info->FindInfo(name, version, force_exact_match); +} + +/* static */ AILibrary *AI::FindLibrary(const char *library, int version) +{ + return AI::scanner_library->FindLibrary(library, version); +} + +/* static */ void AI::Rescan() +{ + TarScanner::DoScan(TarScanner::AI); + + AI::scanner_info->RescanDir(); + AI::scanner_library->RescanDir(); + ResetConfig(); + + InvalidateWindowData(WC_AI_LIST, 0, 1); + SetWindowClassesDirty(WC_AI_DEBUG); + InvalidateWindowClassesData(WC_AI_SETTINGS); +} + +#if defined(ENABLE_NETWORK) + +/** + * Check whether we have an AI (library) with the exact characteristics as ci. + * @param ci the characteristics to search on (shortname and md5sum) + * @param md5sum whether to check the MD5 checksum + * @return true iff we have an AI (library) matching. + */ +/* static */ bool AI::HasAI(const ContentInfo *ci, bool md5sum) +{ + return AI::scanner_info->HasScript(ci, md5sum); +} + +/* static */ bool AI::HasAILibrary(const ContentInfo *ci, bool md5sum) +{ + return AI::scanner_library->HasScript(ci, md5sum); +} + +#endif /* defined(ENABLE_NETWORK) */ + +/* static */ AIScannerInfo *AI::GetScannerInfo() +{ + return AI::scanner_info; +} + +/* static */ AIScannerLibrary *AI::GetScannerLibrary() +{ + return AI::scanner_library; +} + diff --git a/src/ai/ai_gui.cpp b/src/ai/ai_gui.cpp new file mode 100644 index 0000000..0c557d7 --- /dev/null +++ b/src/ai/ai_gui.cpp @@ -0,0 +1,1544 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file ai_gui.cpp %Window for configuring the AIs */ + +#include "../stdafx.h" +#include "../table/sprites.h" +#include "../error.h" +#include "../settings_gui.h" +#include "../querystring_gui.h" +#include "../stringfilter_type.h" +#include "../company_base.h" +#include "../company_gui.h" +#include "../strings_func.h" +#include "../window_func.h" +#include "../gfx_func.h" +#include "../command_func.h" +#include "../network/network.h" +#include "../settings_func.h" +#include "../network/network_content.h" +#include "../textfile_gui.h" +#include "../widgets/dropdown_type.h" +#include "../widgets/dropdown_func.h" +#include "../hotkeys.h" + +#include "ai.hpp" +#include "ai_gui.hpp" +#include "../script/api/script_log.hpp" +#include "ai_config.hpp" +#include "ai_info.hpp" +#include "ai_instance.hpp" +#include "../game/game.hpp" +#include "../game/game_config.hpp" +#include "../game/game_info.hpp" +#include "../game/game_instance.hpp" + +#include "table/strings.h" + +#include + +#include "../safeguards.h" + +static ScriptConfig *GetConfig(CompanyID slot) +{ + if (slot == OWNER_DEITY) return GameConfig::GetConfig(); + return AIConfig::GetConfig(slot); +} + +/** + * Window that let you choose an available AI. + */ +struct AIListWindow : public Window { + const ScriptInfoList *info_list; ///< The list of Scripts. + int selected; ///< The currently selected Script. + CompanyID slot; ///< The company we're selecting a new Script for. + int line_height; ///< Height of a row in the matrix widget. + Scrollbar *vscroll; ///< Cache of the vertical scrollbar. + + /** + * Constructor for the window. + * @param desc The description of the window. + * @param slot The company we're changing the AI for. + */ + AIListWindow(WindowDesc *desc, CompanyID slot) : Window(desc), + slot(slot) + { + if (slot == OWNER_DEITY) { + this->info_list = Game::GetUniqueInfoList(); + } else { + this->info_list = AI::GetUniqueInfoList(); + } + + this->CreateNestedTree(); + this->vscroll = this->GetScrollbar(WID_AIL_SCROLLBAR); + this->FinishInitNested(); // Initializes 'this->line_height' as side effect. + + this->vscroll->SetCount((int)this->info_list->size() + 1); + + /* Try if we can find the currently selected AI */ + this->selected = -1; + if (GetConfig(slot)->HasScript()) { + ScriptInfo *info = GetConfig(slot)->GetInfo(); + int i = 0; + for (ScriptInfoList::const_iterator it = this->info_list->begin(); it != this->info_list->end(); it++, i++) { + if ((*it).second == info) { + this->selected = i; + break; + } + } + } + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_AIL_CAPTION: + SetDParam(0, (this->slot == OWNER_DEITY) ? STR_AI_LIST_CAPTION_GAMESCRIPT : STR_AI_LIST_CAPTION_AI); + break; + } + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + if (widget == WID_AIL_LIST) { + this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; + + resize->width = 1; + resize->height = this->line_height; + size->height = 5 * this->line_height; + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_AIL_LIST: { + /* Draw a list of all available AIs. */ + int y = this->GetWidget(WID_AIL_LIST)->pos_y; + /* First AI in the list is hardcoded to random */ + if (this->vscroll->IsVisible(0)) { + DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_LEFT, y + WD_MATRIX_TOP, this->slot == OWNER_DEITY ? STR_AI_CONFIG_NONE : STR_AI_CONFIG_RANDOM_AI, this->selected == -1 ? TC_WHITE : TC_ORANGE); + y += this->line_height; + } + ScriptInfoList::const_iterator it = this->info_list->begin(); + for (int i = 1; it != this->info_list->end(); i++, it++) { + if (this->vscroll->IsVisible(i)) { + DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, y + WD_MATRIX_TOP, (*it).second->GetName(), (this->selected == i - 1) ? TC_WHITE : TC_ORANGE); + y += this->line_height; + } + } + break; + } + case WID_AIL_INFO_BG: { + AIInfo *selected_info = NULL; + ScriptInfoList::const_iterator it = this->info_list->begin(); + for (int i = 1; selected_info == NULL && it != this->info_list->end(); i++, it++) { + if (this->selected == i - 1) selected_info = static_cast((*it).second); + } + /* Some info about the currently selected AI. */ + if (selected_info != NULL) { + int y = r.top + WD_FRAMERECT_TOP; + SetDParamStr(0, selected_info->GetAuthor()); + DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, STR_AI_LIST_AUTHOR); + y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; + SetDParam(0, selected_info->GetVersion()); + DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, STR_AI_LIST_VERSION); + y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; + if (selected_info->GetURL() != NULL) { + SetDParamStr(0, selected_info->GetURL()); + DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, STR_AI_LIST_URL); + y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; + } + SetDParamStr(0, selected_info->GetDescription()); + DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, r.bottom - WD_FRAMERECT_BOTTOM, STR_JUST_RAW_STRING, TC_WHITE); + } + break; + } + } + } + + /** + * Changes the AI of the current slot. + */ + void ChangeAI() + { + if (this->selected == -1) { + GetConfig(slot)->Change(NULL); + } else { + ScriptInfoList::const_iterator it = this->info_list->begin(); + for (int i = 0; i < this->selected; i++) it++; + GetConfig(slot)->Change((*it).second->GetName(), (*it).second->GetVersion()); + } + InvalidateWindowData(WC_GAME_OPTIONS, WN_GAME_OPTIONS_AI); + InvalidateWindowClassesData(WC_AI_SETTINGS); + DeleteWindowByClass(WC_QUERY_STRING); + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_AIL_LIST: { // Select one of the AIs + int sel = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_AIL_LIST, 0, this->line_height) - 1; + if (sel < (int)this->info_list->size()) { + this->selected = sel; + this->SetDirty(); + if (click_count > 1) { + this->ChangeAI(); + delete this; + } + } + break; + } + + case WID_AIL_ACCEPT: { + this->ChangeAI(); + delete this; + break; + } + + case WID_AIL_CANCEL: + delete this; + break; + } + } + + virtual void OnResize() + { + this->vscroll->SetCapacityFromWidget(this, WID_AIL_LIST); + } + + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (_game_mode == GM_NORMAL && Company::IsValidID(this->slot)) { + delete this; + return; + } + + if (!gui_scope) return; + + this->vscroll->SetCount((int)this->info_list->size() + 1); + + /* selected goes from -1 .. length of ai list - 1. */ + this->selected = min(this->selected, this->vscroll->GetCount() - 2); + } +}; + +/** Widgets for the AI list window. */ +static const NWidgetPart _nested_ai_list_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_MAUVE), + NWidget(WWT_CAPTION, COLOUR_MAUVE, WID_AIL_CAPTION), SetDataTip(STR_AI_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_DEFSIZEBOX, COLOUR_MAUVE), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_MAUVE, WID_AIL_LIST), SetMinimalSize(188, 112), SetFill(1, 1), SetResize(1, 1), SetMatrixDataTip(1, 0, STR_AI_LIST_TOOLTIP), SetScrollbar(WID_AIL_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_AIL_SCROLLBAR), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_MAUVE, WID_AIL_INFO_BG), SetMinimalTextLines(8, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM), SetResize(1, 0), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_AIL_ACCEPT), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_AI_LIST_ACCEPT, STR_AI_LIST_ACCEPT_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_AIL_CANCEL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_AI_LIST_CANCEL, STR_AI_LIST_CANCEL_TOOLTIP), + EndContainer(), + NWidget(WWT_RESIZEBOX, COLOUR_MAUVE), + EndContainer(), +}; + +/** Window definition for the ai list window. */ +static WindowDesc _ai_list_desc( + WDP_CENTER, "settings_script_list", 200, 234, + WC_AI_LIST, WC_NONE, + 0, + _nested_ai_list_widgets, lengthof(_nested_ai_list_widgets) +); + +/** + * Open the AI list window to chose an AI for the given company slot. + * @param slot The slot to change the AI of. + */ +static void ShowAIListWindow(CompanyID slot) +{ + DeleteWindowByClass(WC_AI_LIST); + new AIListWindow(&_ai_list_desc, slot); +} + +/** + * Window for settings the parameters of an AI. + */ +struct AISettingsWindow : public Window { + CompanyID slot; ///< The currently show company's setting. + ScriptConfig *ai_config; ///< The configuration we're modifying. + int clicked_button; ///< The button we clicked. + bool clicked_increase; ///< Whether we clicked the increase or decrease button. + bool clicked_dropdown; ///< Whether the dropdown is open. + bool closing_dropdown; ///< True, if the dropdown list is currently closing. + int timeout; ///< Timeout for unclicking the button. + int clicked_row; ///< The clicked row of settings. + int line_height; ///< Height of a row in the matrix widget. + Scrollbar *vscroll; ///< Cache of the vertical scrollbar. + typedef std::vector VisibleSettingsList; + VisibleSettingsList visible_settings; ///< List of visible AI settings + + /** + * Constructor for the window. + * @param desc The description of the window. + * @param slot The company we're changing the settings for. + */ + AISettingsWindow(WindowDesc *desc, CompanyID slot) : Window(desc), + slot(slot), + clicked_button(-1), + clicked_dropdown(false), + closing_dropdown(false), + timeout(0) + { + this->ai_config = GetConfig(slot); + this->RebuildVisibleSettings(); + + this->CreateNestedTree(); + this->vscroll = this->GetScrollbar(WID_AIS_SCROLLBAR); + this->FinishInitNested(slot); // Initializes 'this->line_height' as side effect. + + this->SetWidgetDisabledState(WID_AIS_RESET, _game_mode != GM_MENU && Company::IsValidID(this->slot)); + + this->vscroll->SetCount((int)this->visible_settings.size()); + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_AIS_CAPTION: + SetDParam(0, (this->slot == OWNER_DEITY) ? STR_AI_SETTINGS_CAPTION_GAMESCRIPT : STR_AI_SETTINGS_CAPTION_AI); + break; + } + } + + /** + * Rebuilds the list of visible settings. AI settings with the flag + * AICONFIG_AI_DEVELOPER set will only be visible if the game setting + * gui.ai_developer_tools is enabled. + */ + void RebuildVisibleSettings() + { + visible_settings.clear(); + + ScriptConfigItemList::const_iterator it = this->ai_config->GetConfigList()->begin(); + for (; it != this->ai_config->GetConfigList()->end(); it++) { + bool no_hide = (it->flags & SCRIPTCONFIG_DEVELOPER) == 0; + if (no_hide || _settings_client.gui.ai_developer_tools) { + visible_settings.push_back(&(*it)); + } + } + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + if (widget == WID_AIS_BACKGROUND) { + this->line_height = max(SETTING_BUTTON_HEIGHT, FONT_HEIGHT_NORMAL) + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; + + resize->width = 1; + resize->height = this->line_height; + size->height = 5 * this->line_height; + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + if (widget != WID_AIS_BACKGROUND) return; + + ScriptConfig *config = this->ai_config; + VisibleSettingsList::const_iterator it = this->visible_settings.begin(); + int i = 0; + for (; !this->vscroll->IsVisible(i); i++) it++; + + bool rtl = _current_text_dir == TD_RTL; + uint buttons_left = rtl ? r.right - SETTING_BUTTON_WIDTH - 3 : r.left + 4; + uint text_left = r.left + (rtl ? WD_FRAMERECT_LEFT : SETTING_BUTTON_WIDTH + 8); + uint text_right = r.right - (rtl ? SETTING_BUTTON_WIDTH + 8 : WD_FRAMERECT_RIGHT); + + + int y = r.top; + int button_y_offset = (this->line_height - SETTING_BUTTON_HEIGHT) / 2; + int text_y_offset = (this->line_height - FONT_HEIGHT_NORMAL) / 2; + for (; this->vscroll->IsVisible(i) && it != visible_settings.end(); i++, it++) { + const ScriptConfigItem &config_item = **it; + int current_value = config->GetSetting((config_item).name); + bool editable = _game_mode == GM_MENU || ((this->slot != OWNER_DEITY) && !Company::IsValidID(this->slot)) || (config_item.flags & SCRIPTCONFIG_INGAME) != 0; + + StringID str; + TextColour colour; + uint idx = 0; + if (StrEmpty(config_item.description)) { + if (!strcmp(config_item.name, "start_date")) { + /* Build-in translation */ + str = STR_AI_SETTINGS_START_DELAY; + colour = TC_LIGHT_BLUE; + } else { + str = STR_JUST_STRING; + colour = TC_ORANGE; + } + } else { + str = STR_AI_SETTINGS_SETTING; + colour = TC_LIGHT_BLUE; + SetDParamStr(idx++, config_item.description); + } + + if ((config_item.flags & SCRIPTCONFIG_BOOLEAN) != 0) { + DrawBoolButton(buttons_left, y + button_y_offset, current_value != 0, editable); + SetDParam(idx++, current_value == 0 ? STR_CONFIG_SETTING_OFF : STR_CONFIG_SETTING_ON); + } else { + if (config_item.complete_labels) { + DrawDropDownButton(buttons_left, y + button_y_offset, COLOUR_YELLOW, this->clicked_row == i && clicked_dropdown, editable); + } else { + DrawArrowButtons(buttons_left, y + button_y_offset, COLOUR_YELLOW, (this->clicked_button == i) ? 1 + (this->clicked_increase != rtl) : 0, editable && current_value > config_item.min_value, editable && current_value < config_item.max_value); + } + if (config_item.labels != NULL && config_item.labels->Contains(current_value)) { + SetDParam(idx++, STR_JUST_RAW_STRING); + SetDParamStr(idx++, config_item.labels->Find(current_value)->second); + } else { + SetDParam(idx++, STR_JUST_INT); + SetDParam(idx++, current_value); + } + } + + DrawString(text_left, text_right, y + text_y_offset, str, colour); + y += this->line_height; + } + } + + virtual void OnPaint() + { + if (this->closing_dropdown) { + this->closing_dropdown = false; + this->clicked_dropdown = false; + } + this->DrawWidgets(); + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_AIS_BACKGROUND: { + const NWidgetBase *wid = this->GetWidget(WID_AIS_BACKGROUND); + int num = (pt.y - wid->pos_y) / this->line_height + this->vscroll->GetPosition(); + if (num >= (int)this->visible_settings.size()) break; + + VisibleSettingsList::const_iterator it = this->visible_settings.begin(); + for (int i = 0; i < num; i++) it++; + const ScriptConfigItem config_item = **it; + if (_game_mode == GM_NORMAL && ((this->slot == OWNER_DEITY) || Company::IsValidID(this->slot)) && (config_item.flags & SCRIPTCONFIG_INGAME) == 0) return; + + if (this->clicked_row != num) { + DeleteChildWindows(WC_QUERY_STRING); + HideDropDownMenu(this); + this->clicked_row = num; + this->clicked_dropdown = false; + } + + bool bool_item = (config_item.flags & SCRIPTCONFIG_BOOLEAN) != 0; + + int x = pt.x - wid->pos_x; + if (_current_text_dir == TD_RTL) x = wid->current_x - 1 - x; + x -= 4; + + /* One of the arrows is clicked (or green/red rect in case of bool value) */ + int old_val = this->ai_config->GetSetting(config_item.name); + if (!bool_item && IsInsideMM(x, 0, SETTING_BUTTON_WIDTH) && config_item.complete_labels) { + if (this->clicked_dropdown) { + /* unclick the dropdown */ + HideDropDownMenu(this); + this->clicked_dropdown = false; + this->closing_dropdown = false; + } else { + const NWidgetBase *wid = this->GetWidget(WID_AIS_BACKGROUND); + int rel_y = (pt.y - (int)wid->pos_y) % this->line_height; + + Rect wi_rect; + wi_rect.left = pt.x - (_current_text_dir == TD_RTL ? SETTING_BUTTON_WIDTH - 1 - x : x); + wi_rect.right = wi_rect.left + SETTING_BUTTON_WIDTH - 1; + wi_rect.top = pt.y - rel_y + (this->line_height - SETTING_BUTTON_HEIGHT) / 2; + wi_rect.bottom = wi_rect.top + SETTING_BUTTON_HEIGHT - 1; + + /* For dropdowns we also have to check the y position thoroughly, the mouse may not above the just opening dropdown */ + if (pt.y >= wi_rect.top && pt.y <= wi_rect.bottom) { + this->clicked_dropdown = true; + this->closing_dropdown = false; + + DropDownList *list = new DropDownList(); + for (int i = config_item.min_value; i <= config_item.max_value; i++) { + *list->Append() = new DropDownListCharStringItem(config_item.labels->Find(i)->second, i, false); + } + + ShowDropDownListAt(this, list, old_val, -1, wi_rect, COLOUR_ORANGE, true); + } + } + } else if (IsInsideMM(x, 0, SETTING_BUTTON_WIDTH)) { + int new_val = old_val; + if (bool_item) { + new_val = !new_val; + } else if (x >= SETTING_BUTTON_WIDTH / 2) { + /* Increase button clicked */ + new_val += config_item.step_size; + if (new_val > config_item.max_value) new_val = config_item.max_value; + this->clicked_increase = true; + } else { + /* Decrease button clicked */ + new_val -= config_item.step_size; + if (new_val < config_item.min_value) new_val = config_item.min_value; + this->clicked_increase = false; + } + + if (new_val != old_val) { + this->ai_config->SetSetting(config_item.name, new_val); + this->clicked_button = num; + this->timeout = 5; + } + } else if (!bool_item && !config_item.complete_labels) { + /* Display a query box so users can enter a custom value. */ + SetDParam(0, old_val); + ShowQueryString(STR_JUST_INT, STR_CONFIG_SETTING_QUERY_CAPTION, 10, this, CS_NUMERAL, QSF_NONE); + } + this->SetDirty(); + break; + } + + case WID_AIS_ACCEPT: + delete this; + break; + + case WID_AIS_RESET: + if (_game_mode == GM_MENU || !Company::IsValidID(this->slot)) { + this->ai_config->ResetSettings(); + this->SetDirty(); + } + break; + } + } + + virtual void OnQueryTextFinished(char *str) + { + if (StrEmpty(str)) return; + ScriptConfigItemList::const_iterator it = this->ai_config->GetConfigList()->begin(); + for (int i = 0; i < this->clicked_row; i++) it++; + if (_game_mode == GM_NORMAL && ((this->slot == OWNER_DEITY) || Company::IsValidID(this->slot)) && (it->flags & SCRIPTCONFIG_INGAME) == 0) return; + int32 value = atoi(str); + this->ai_config->SetSetting((*it).name, value); + this->SetDirty(); + } + + virtual void OnDropdownSelect(int widget, int index) + { + assert(this->clicked_dropdown); + ScriptConfigItemList::const_iterator it = this->ai_config->GetConfigList()->begin(); + for (int i = 0; i < this->clicked_row; i++) it++; + if (_game_mode == GM_NORMAL && ((this->slot == OWNER_DEITY) || Company::IsValidID(this->slot)) && (it->flags & SCRIPTCONFIG_INGAME) == 0) return; + this->ai_config->SetSetting((*it).name, index); + this->SetDirty(); + } + + virtual void OnDropdownClose(Point pt, int widget, int index, bool instant_close) + { + /* We cannot raise the dropdown button just yet. OnClick needs some hint, whether + * the same dropdown button was clicked again, and then not open the dropdown again. + * So, we only remember that it was closed, and process it on the next OnPaint, which is + * after OnClick. */ + assert(this->clicked_dropdown); + this->closing_dropdown = true; + this->SetDirty(); + } + + virtual void OnResize() + { + this->vscroll->SetCapacityFromWidget(this, WID_AIS_BACKGROUND); + } + + virtual void OnTick() + { + if (--this->timeout == 0) { + this->clicked_button = -1; + this->SetDirty(); + } + } + + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + this->RebuildVisibleSettings(); + } +}; + +/** Widgets for the AI settings window. */ +static const NWidgetPart _nested_ai_settings_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_MAUVE), + NWidget(WWT_CAPTION, COLOUR_MAUVE, WID_AIS_CAPTION), SetDataTip(STR_AI_SETTINGS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_DEFSIZEBOX, COLOUR_MAUVE), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_MAUVE, WID_AIS_BACKGROUND), SetMinimalSize(188, 182), SetResize(1, 1), SetFill(1, 0), SetMatrixDataTip(1, 0, STR_NULL), SetScrollbar(WID_AIS_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_AIS_SCROLLBAR), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_AIS_ACCEPT), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_AI_SETTINGS_CLOSE, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_AIS_RESET), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_AI_SETTINGS_RESET, STR_NULL), + EndContainer(), + NWidget(WWT_RESIZEBOX, COLOUR_MAUVE), + EndContainer(), +}; + +/** Window definition for the AI settings window. */ +static WindowDesc _ai_settings_desc( + WDP_CENTER, "settings_script", 500, 208, + WC_AI_SETTINGS, WC_NONE, + 0, + _nested_ai_settings_widgets, lengthof(_nested_ai_settings_widgets) +); + +/** + * Open the AI settings window to change the AI settings for an AI. + * @param slot The CompanyID of the AI to change the settings. + */ +static void ShowAISettingsWindow(CompanyID slot) +{ + DeleteWindowByClass(WC_AI_LIST); + DeleteWindowByClass(WC_AI_SETTINGS); + new AISettingsWindow(&_ai_settings_desc, slot); +} + + +/** Window for displaying the textfile of a AI. */ +struct ScriptTextfileWindow : public TextfileWindow { + CompanyID slot; ///< View the textfile of this CompanyID slot. + + ScriptTextfileWindow(TextfileType file_type, CompanyID slot) : TextfileWindow(file_type), slot(slot) + { + const char *textfile = GetConfig(slot)->GetTextfile(file_type, slot); + this->LoadTextfile(textfile, (slot == OWNER_DEITY) ? GAME_DIR : AI_DIR); + } + + /* virtual */ void SetStringParameters(int widget) const + { + if (widget == WID_TF_CAPTION) { + SetDParam(0, (slot == OWNER_DEITY) ? STR_CONTENT_TYPE_GAME_SCRIPT : STR_CONTENT_TYPE_AI); + SetDParamStr(1, GetConfig(slot)->GetName()); + } + } +}; + +/** + * Open the AI version of the textfile window. + * @param file_type The type of textfile to display. + * @param slot The slot the Script is using. + */ +void ShowScriptTextfileWindow(TextfileType file_type, CompanyID slot) +{ + DeleteWindowByClass(WC_TEXTFILE); + new ScriptTextfileWindow(file_type, slot); +} + + +/** Widgets for the configure AI window. */ +static const NWidgetPart _nested_ai_config_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_MAUVE), + NWidget(WWT_CAPTION, COLOUR_MAUVE), SetDataTip(STR_AI_CONFIG_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_MAUVE, WID_AIC_BACKGROUND), + NWidget(NWID_VERTICAL), SetPIP(4, 4, 4), + NWidget(NWID_HORIZONTAL), SetPIP(7, 0, 7), + NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_AIC_DECREASE), SetFill(0, 1), SetDataTip(AWV_DECREASE, STR_NULL), + NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_AIC_INCREASE), SetFill(0, 1), SetDataTip(AWV_INCREASE, STR_NULL), + NWidget(NWID_SPACER), SetMinimalSize(6, 0), + NWidget(WWT_TEXT, COLOUR_MAUVE, WID_AIC_NUMBER), SetDataTip(STR_DIFFICULTY_LEVEL_SETTING_MAXIMUM_NO_COMPETITORS, STR_NULL), SetFill(1, 0), SetPadding(1, 0, 0, 0), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_MOVE_UP), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_AI_CONFIG_MOVE_UP, STR_AI_CONFIG_MOVE_UP_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_MOVE_DOWN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_AI_CONFIG_MOVE_DOWN, STR_AI_CONFIG_MOVE_DOWN_TOOLTIP), + EndContainer(), + EndContainer(), + NWidget(WWT_FRAME, COLOUR_MAUVE), SetDataTip(STR_AI_CONFIG_AI, STR_NULL), SetPadding(0, 5, 0, 5), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_MAUVE, WID_AIC_LIST), SetMinimalSize(288, 112), SetFill(1, 0), SetMatrixDataTip(1, 8, STR_AI_CONFIG_AILIST_TOOLTIP), SetScrollbar(WID_AIC_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_AIC_SCROLLBAR), + EndContainer(), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 9), + NWidget(WWT_FRAME, COLOUR_MAUVE), SetDataTip(STR_AI_CONFIG_GAMESCRIPT, STR_NULL), SetPadding(0, 5, 4, 5), + NWidget(WWT_MATRIX, COLOUR_MAUVE, WID_AIC_GAMELIST), SetMinimalSize(288, 14), SetFill(1, 0), SetMatrixDataTip(1, 1, STR_AI_CONFIG_GAMELIST_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CHANGE), SetFill(1, 0), SetMinimalSize(93, 12), SetDataTip(STR_AI_CONFIG_CHANGE, STR_AI_CONFIG_CHANGE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CONFIGURE), SetFill(1, 0), SetMinimalSize(93, 12), SetDataTip(STR_AI_CONFIG_CONFIGURE, STR_AI_CONFIG_CONFIGURE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CLOSE), SetFill(1, 0), SetMinimalSize(93, 12), SetDataTip(STR_AI_SETTINGS_CLOSE, STR_NULL), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), + EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CONTENT_DOWNLOAD), SetFill(1, 0), SetMinimalSize(279, 12), SetPadding(0, 7, 9, 7), SetDataTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT), + EndContainer(), +}; + +/** Window definition for the configure AI window. */ +static WindowDesc _ai_config_desc( + WDP_CENTER, "settings_script_config", 0, 0, + WC_GAME_OPTIONS, WC_NONE, + 0, + _nested_ai_config_widgets, lengthof(_nested_ai_config_widgets) +); + +/** + * Window to configure which AIs will start. + */ +struct AIConfigWindow : public Window { + CompanyID selected_slot; ///< The currently selected AI slot or \c INVALID_COMPANY. + int line_height; ///< Height of a single AI-name line. + Scrollbar *vscroll; ///< Cache of the vertical scrollbar. + + AIConfigWindow() : Window(&_ai_config_desc) + { + this->InitNested(WN_GAME_OPTIONS_AI); // Initializes 'this->line_height' as a side effect. + this->vscroll = this->GetScrollbar(WID_AIC_SCROLLBAR); + this->selected_slot = INVALID_COMPANY; + NWidgetCore *nwi = this->GetWidget(WID_AIC_LIST); + this->vscroll->SetCapacity(nwi->current_y / this->line_height); + this->vscroll->SetCount(MAX_COMPANIES); + this->OnInvalidateData(0); + } + + ~AIConfigWindow() + { + DeleteWindowByClass(WC_AI_LIST); + DeleteWindowByClass(WC_AI_SETTINGS); + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_AIC_NUMBER: + SetDParam(0, GetGameSettings().difficulty.max_no_competitors); + break; + case WID_AIC_CHANGE: + switch (selected_slot) { + case OWNER_DEITY: + SetDParam(0, STR_AI_CONFIG_CHANGE_GAMESCRIPT); + break; + + case INVALID_COMPANY: + SetDParam(0, STR_AI_CONFIG_CHANGE_NONE); + break; + + default: + SetDParam(0, STR_AI_CONFIG_CHANGE_AI); + break; + } + break; + } + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_AIC_GAMELIST: + this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; + size->height = 1 * this->line_height; + break; + + case WID_AIC_LIST: + this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; + size->height = 8 * this->line_height; + break; + } + } + + /** + * Can the AI config in the given company slot be edited? + * @param slot The slot to query. + * @return True if and only if the given AI Config slot can e edited. + */ + static bool IsEditable(CompanyID slot) + { + if (slot == OWNER_DEITY) return _game_mode != GM_NORMAL || Game::GetInstance() != NULL; + + if (_game_mode != GM_NORMAL) { + return slot > 0 && slot <= GetGameSettings().difficulty.max_no_competitors; + } + if (Company::IsValidID(slot) || slot < 0) return false; + + int max_slot = GetGameSettings().difficulty.max_no_competitors; + for (CompanyID cid = COMPANY_FIRST; cid < (CompanyID)max_slot && cid < MAX_COMPANIES; cid++) { + if (Company::IsValidHumanID(cid)) max_slot++; + } + return slot < max_slot; + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_AIC_GAMELIST: { + StringID text = STR_AI_CONFIG_NONE; + + if (GameConfig::GetConfig()->GetInfo() != NULL) { + SetDParamStr(0, GameConfig::GetConfig()->GetInfo()->GetName()); + text = STR_JUST_RAW_STRING; + } + + DrawString(r.left + 10, r.right - 10, r.top + WD_MATRIX_TOP, text, + (this->selected_slot == OWNER_DEITY) ? TC_WHITE : (IsEditable(OWNER_DEITY) ? TC_ORANGE : TC_SILVER)); + + break; + } + + case WID_AIC_LIST: { + int y = r.top; + for (int i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < MAX_COMPANIES; i++) { + StringID text; + + if ((_game_mode != GM_NORMAL && i == 0) || (_game_mode == GM_NORMAL && Company::IsValidHumanID(i))) { + text = STR_AI_CONFIG_HUMAN_PLAYER; + } else if (AIConfig::GetConfig((CompanyID)i)->GetInfo() != NULL) { + SetDParamStr(0, AIConfig::GetConfig((CompanyID)i)->GetInfo()->GetName()); + text = STR_JUST_RAW_STRING; + } else { + text = STR_AI_CONFIG_RANDOM_AI; + } + DrawString(r.left + 10, r.right - 10, y + WD_MATRIX_TOP, text, + (this->selected_slot == i) ? TC_WHITE : (IsEditable((CompanyID)i) ? TC_ORANGE : TC_SILVER)); + y += this->line_height; + } + break; + } + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + if (widget >= WID_AIC_TEXTFILE && widget < WID_AIC_TEXTFILE + TFT_END) { + if (this->selected_slot == INVALID_COMPANY || GetConfig(this->selected_slot) == NULL) return; + + ShowScriptTextfileWindow((TextfileType)(widget - WID_AIC_TEXTFILE), this->selected_slot); + return; + } + + switch (widget) { + case WID_AIC_DECREASE: + case WID_AIC_INCREASE: { + int new_value; + if (widget == WID_AIC_DECREASE) { + new_value = max(0, GetGameSettings().difficulty.max_no_competitors - 1); + } else { + new_value = min(MAX_COMPANIES - 1, GetGameSettings().difficulty.max_no_competitors + 1); + } + IConsoleSetSetting("difficulty.max_no_competitors", new_value); + this->InvalidateData(); + break; + } + + case WID_AIC_GAMELIST: { + this->selected_slot = OWNER_DEITY; + this->InvalidateData(); + if (click_count > 1 && this->selected_slot != INVALID_COMPANY && _game_mode != GM_NORMAL) ShowAIListWindow((CompanyID)this->selected_slot); + break; + } + + case WID_AIC_LIST: { // Select a slot + this->selected_slot = (CompanyID)this->vscroll->GetScrolledRowFromWidget(pt.y, this, widget, 0, this->line_height); + this->InvalidateData(); + if (click_count > 1 && this->selected_slot != INVALID_COMPANY) ShowAIListWindow((CompanyID)this->selected_slot); + break; + } + + case WID_AIC_MOVE_UP: + if (IsEditable(this->selected_slot) && IsEditable((CompanyID)(this->selected_slot - 1))) { + Swap(GetGameSettings().ai_config[this->selected_slot], GetGameSettings().ai_config[this->selected_slot - 1]); + this->selected_slot--; + this->vscroll->ScrollTowards(this->selected_slot); + this->InvalidateData(); + } + break; + + case WID_AIC_MOVE_DOWN: + if (IsEditable(this->selected_slot) && IsEditable((CompanyID)(this->selected_slot + 1))) { + Swap(GetGameSettings().ai_config[this->selected_slot], GetGameSettings().ai_config[this->selected_slot + 1]); + this->selected_slot++; + this->vscroll->ScrollTowards(this->selected_slot); + this->InvalidateData(); + } + break; + + case WID_AIC_CHANGE: // choose other AI + ShowAIListWindow((CompanyID)this->selected_slot); + break; + + case WID_AIC_CONFIGURE: // change the settings for an AI + ShowAISettingsWindow((CompanyID)this->selected_slot); + break; + + case WID_AIC_CLOSE: + delete this; + break; + + case WID_AIC_CONTENT_DOWNLOAD: + if (!_network_available) { + ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR); + } else { +#if defined(ENABLE_NETWORK) + ShowNetworkContentListWindow(NULL, CONTENT_TYPE_AI); + _network_content_client.RequestContentList(CONTENT_TYPE_GAME); +#endif + } + break; + } + } + + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (!IsEditable(this->selected_slot)) { + this->selected_slot = INVALID_COMPANY; + } + + if (!gui_scope) return; + + this->SetWidgetDisabledState(WID_AIC_DECREASE, GetGameSettings().difficulty.max_no_competitors == 0); + this->SetWidgetDisabledState(WID_AIC_INCREASE, GetGameSettings().difficulty.max_no_competitors == MAX_COMPANIES - 1); + this->SetWidgetDisabledState(WID_AIC_CHANGE, (this->selected_slot == OWNER_DEITY && _game_mode == GM_NORMAL) || this->selected_slot == INVALID_COMPANY); + this->SetWidgetDisabledState(WID_AIC_CONFIGURE, this->selected_slot == INVALID_COMPANY || GetConfig(this->selected_slot)->GetConfigList()->size() == 0); + this->SetWidgetDisabledState(WID_AIC_MOVE_UP, this->selected_slot == OWNER_DEITY || this->selected_slot == INVALID_COMPANY || !IsEditable((CompanyID)(this->selected_slot - 1))); + this->SetWidgetDisabledState(WID_AIC_MOVE_DOWN, this->selected_slot == OWNER_DEITY || this->selected_slot == INVALID_COMPANY || !IsEditable((CompanyID)(this->selected_slot + 1))); + + for (TextfileType tft = TFT_BEGIN; tft < TFT_END; tft++) { + this->SetWidgetDisabledState(WID_AIC_TEXTFILE + tft, this->selected_slot == INVALID_COMPANY || (GetConfig(this->selected_slot)->GetTextfile(tft, this->selected_slot) == NULL)); + } + } +}; + +/** Open the AI config window. */ +void ShowAIConfigWindow() +{ + DeleteWindowByClass(WC_GAME_OPTIONS); + new AIConfigWindow(); +} + +/** + * Set the widget colour of a button based on the + * state of the script. (dead or alive) + * @param button the button to update. + * @param dead true if the script is dead, otherwise false. + * @param paused true if the script is paused, otherwise false. + * @return true if the colour was changed and the window need to be marked as dirty. + */ +static bool SetScriptButtonColour(NWidgetCore &button, bool dead, bool paused) +{ + /* Dead scripts are indicated with red background and + * paused scripts are indicated with yellow background. */ + Colours colour = dead ? COLOUR_RED : + (paused ? COLOUR_YELLOW : COLOUR_GREY); + if (button.colour != colour) { + button.colour = colour; + return true; + } + return false; +} + +/** + * Window with everything an AI prints via ScriptLog. + */ +struct AIDebugWindow : public Window { + static const int top_offset; ///< Offset of the text at the top of the WID_AID_LOG_PANEL. + static const int bottom_offset; ///< Offset of the text at the bottom of the WID_AID_LOG_PANEL. + + static const uint MAX_BREAK_STR_STRING_LENGTH = 256; ///< Maximum length of the break string. + + static CompanyID ai_debug_company; ///< The AI that is (was last) being debugged. + int redraw_timer; ///< Timer for redrawing the window, otherwise it'll happen every tick. + int last_vscroll_pos; ///< Last position of the scrolling. + bool autoscroll; ///< Whether automatically scrolling should be enabled or not. + bool show_break_box; ///< Whether the break/debug box is visible. + static bool break_check_enabled; ///< Stop an AI when it prints a matching string + static char break_string[MAX_BREAK_STR_STRING_LENGTH]; ///< The string to match to the AI output + QueryString break_editbox; ///< Break editbox + static StringFilter break_string_filter; ///< Log filter for break. + static bool case_sensitive_break_check; ///< Is the matching done case-sensitive + int highlight_row; ///< The output row that matches the given string, or -1 + Scrollbar *vscroll; ///< Cache of the vertical scrollbar. + + ScriptLog::LogData *GetLogPointer() const + { + if (ai_debug_company == OWNER_DEITY) return (ScriptLog::LogData *)Game::GetInstance()->GetLogPointer(); + return (ScriptLog::LogData *)Company::Get(ai_debug_company)->ai_instance->GetLogPointer(); + } + + /** + * Check whether the currently selected AI/GS is dead. + * @return true if dead. + */ + bool IsDead() const + { + if (ai_debug_company == OWNER_DEITY) { + GameInstance *game = Game::GetInstance(); + return game == NULL || game->IsDead(); + } + return !Company::IsValidAiID(ai_debug_company) || Company::Get(ai_debug_company)->ai_instance->IsDead(); + } + + /** + * Check whether a company is a valid AI company or GS. + * @param company Company to check for validity. + * @return true if company is valid for debugging. + */ + bool IsValidDebugCompany(CompanyID company) const + { + switch (company) { + case INVALID_COMPANY: return false; + case OWNER_DEITY: return Game::GetInstance() != NULL; + default: return Company::IsValidAiID(company); + } + } + + /** + * Ensure that \c ai_debug_company refers to a valid AI company or GS, or is set to #INVALID_COMPANY. + * If no valid company is selected, it selects the first valid AI or GS if any. + */ + void SelectValidDebugCompany() + { + /* Check if the currently selected company is still active. */ + if (this->IsValidDebugCompany(ai_debug_company)) return; + + ai_debug_company = INVALID_COMPANY; + + const Company *c; + FOR_ALL_COMPANIES(c) { + if (c->is_ai) { + ChangeToAI(c->index); + return; + } + } + + /* If no AI is available, see if there is a game script. */ + if (Game::GetInstance() != NULL) ChangeToAI(OWNER_DEITY); + } + + /** + * Constructor for the window. + * @param desc The description of the window. + * @param number The window number (actually unused). + */ + AIDebugWindow(WindowDesc *desc, WindowNumber number) : Window(desc), break_editbox(MAX_BREAK_STR_STRING_LENGTH) + { + this->CreateNestedTree(); + this->vscroll = this->GetScrollbar(WID_AID_SCROLLBAR); + this->show_break_box = _settings_client.gui.ai_developer_tools; + this->GetWidget(WID_AID_BREAK_STRING_WIDGETS)->SetDisplayedPlane(this->show_break_box ? 0 : SZSP_HORIZONTAL); + this->FinishInitNested(number); + + if (!this->show_break_box) break_check_enabled = false; + + this->last_vscroll_pos = 0; + this->autoscroll = true; + this->highlight_row = -1; + + this->querystrings[WID_AID_BREAK_STR_EDIT_BOX] = &this->break_editbox; + + SetWidgetsDisabledState(!this->show_break_box, WID_AID_BREAK_STR_ON_OFF_BTN, WID_AID_BREAK_STR_EDIT_BOX, WID_AID_MATCH_CASE_BTN, WIDGET_LIST_END); + + /* Restore the break string value from static variable */ + this->break_editbox.text.Assign(this->break_string); + + this->SelectValidDebugCompany(); + this->InvalidateData(-1); + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + if (widget == WID_AID_LOG_PANEL) { + resize->height = FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; + size->height = 14 * resize->height + this->top_offset + this->bottom_offset; + } + } + + virtual void OnPaint() + { + this->SelectValidDebugCompany(); + + /* Draw standard stuff */ + this->DrawWidgets(); + + if (this->IsShaded()) return; // Don't draw anything when the window is shaded. + + bool dirty = false; + + /* Paint the company icons */ + for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) { + NWidgetCore *button = this->GetWidget(i + WID_AID_COMPANY_BUTTON_START); + + bool valid = Company::IsValidAiID(i); + + /* Check whether the validity of the company changed */ + dirty |= (button->IsDisabled() == valid); + + /* Mark dead/paused AIs by setting the background colour. */ + bool dead = valid && Company::Get(i)->ai_instance->IsDead(); + bool paused = valid && Company::Get(i)->ai_instance->IsPaused(); + /* Re-paint if the button was updated. + * (note that it is intentional that SetScriptButtonColour is always called) */ + dirty |= SetScriptButtonColour(*button, dead, paused); + + /* Draw company icon only for valid AI companies */ + if (!valid) continue; + + byte offset = (i == ai_debug_company) ? 1 : 0; + DrawCompanyIcon(i, button->pos_x + button->current_x / 2 - 7 + offset, this->GetWidget(WID_AID_COMPANY_BUTTON_START + i)->pos_y + 2 + offset); + } + + /* Set button colour for Game Script. */ + GameInstance *game = Game::GetInstance(); + bool valid = game != NULL; + bool dead = valid && game->IsDead(); + bool paused = valid && game->IsPaused(); + + NWidgetCore *button = this->GetWidget(WID_AID_SCRIPT_GAME); + dirty |= (button->IsDisabled() == valid) || SetScriptButtonColour(*button, dead, paused); + + if (dirty) this->InvalidateData(-1); + + /* If there are no active companies, don't display anything else. */ + if (ai_debug_company == INVALID_COMPANY) return; + + ScriptLog::LogData *log = this->GetLogPointer(); + + int scroll_count = (log == NULL) ? 0 : log->used; + if (this->vscroll->GetCount() != scroll_count) { + this->vscroll->SetCount(scroll_count); + + /* We need a repaint */ + this->SetWidgetDirty(WID_AID_SCROLLBAR); + } + + if (log == NULL) return; + + /* Detect when the user scrolls the window. Enable autoscroll when the + * bottom-most line becomes visible. */ + if (this->last_vscroll_pos != this->vscroll->GetPosition()) { + this->autoscroll = this->vscroll->GetPosition() >= log->used - this->vscroll->GetCapacity(); + } + if (this->autoscroll) { + int scroll_pos = max(0, log->used - this->vscroll->GetCapacity()); + if (scroll_pos != this->vscroll->GetPosition()) { + this->vscroll->SetPosition(scroll_pos); + + /* We need a repaint */ + this->SetWidgetDirty(WID_AID_SCROLLBAR); + this->SetWidgetDirty(WID_AID_LOG_PANEL); + } + } + this->last_vscroll_pos = this->vscroll->GetPosition(); + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_AID_NAME_TEXT: + if (ai_debug_company == OWNER_DEITY) { + const GameInfo *info = Game::GetInfo(); + assert(info != NULL); + SetDParam(0, STR_AI_DEBUG_NAME_AND_VERSION); + SetDParamStr(1, info->GetName()); + SetDParam(2, info->GetVersion()); + } else if (ai_debug_company == INVALID_COMPANY || !Company::IsValidAiID(ai_debug_company)) { + SetDParam(0, STR_EMPTY); + } else { + const AIInfo *info = Company::Get(ai_debug_company)->ai_info; + assert(info != NULL); + SetDParam(0, STR_AI_DEBUG_NAME_AND_VERSION); + SetDParamStr(1, info->GetName()); + SetDParam(2, info->GetVersion()); + } + break; + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + if (ai_debug_company == INVALID_COMPANY) return; + + switch (widget) { + case WID_AID_LOG_PANEL: { + ScriptLog::LogData *log = this->GetLogPointer(); + if (log == NULL) return; + + int y = this->top_offset; + for (int i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < log->used; i++) { + int pos = (i + log->pos + 1 - log->used + log->count) % log->count; + if (log->lines[pos] == NULL) break; + + TextColour colour; + switch (log->type[pos]) { + case ScriptLog::LOG_SQ_INFO: colour = TC_BLACK; break; + case ScriptLog::LOG_SQ_ERROR: colour = TC_RED; break; + case ScriptLog::LOG_INFO: colour = TC_BLACK; break; + case ScriptLog::LOG_WARNING: colour = TC_YELLOW; break; + case ScriptLog::LOG_ERROR: colour = TC_RED; break; + default: colour = TC_BLACK; break; + } + + /* Check if the current line should be highlighted */ + if (pos == this->highlight_row) { + GfxFillRect(r.left + 1, r.top + y, r.right - 1, r.top + y + this->resize.step_height - WD_PAR_VSEP_NORMAL, PC_BLACK); + if (colour == TC_BLACK) colour = TC_WHITE; // Make black text readable by inverting it to white. + } + + DrawString(r.left + 7, r.right - 7, r.top + y, log->lines[pos], colour, SA_LEFT | SA_FORCE); + y += this->resize.step_height; + } + break; + } + } + } + + /** + * Change all settings to select another AI. + * @param show_ai The new AI to show. + */ + void ChangeToAI(CompanyID show_ai) + { + if (!this->IsValidDebugCompany(show_ai)) return; + + ai_debug_company = show_ai; + + this->highlight_row = -1; // The highlight of one AI make little sense for another AI. + + /* Close AI settings window to prevent confusion */ + DeleteWindowByClass(WC_AI_SETTINGS); + + this->InvalidateData(-1); + + this->autoscroll = true; + this->last_vscroll_pos = this->vscroll->GetPosition(); + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + /* Also called for hotkeys, so check for disabledness */ + if (this->IsWidgetDisabled(widget)) return; + + /* Check which button is clicked */ + if (IsInsideMM(widget, WID_AID_COMPANY_BUTTON_START, WID_AID_COMPANY_BUTTON_END + 1)) { + ChangeToAI((CompanyID)(widget - WID_AID_COMPANY_BUTTON_START)); + } + + switch (widget) { + case WID_AID_SCRIPT_GAME: + ChangeToAI(OWNER_DEITY); + break; + + case WID_AID_RELOAD_TOGGLE: + if (ai_debug_company == OWNER_DEITY) break; + /* First kill the company of the AI, then start a new one. This should start the current AI again */ + DoCommandP(0, 2 | ai_debug_company << 16, CRR_MANUAL, CMD_COMPANY_CTRL); + DoCommandP(0, 1 | ai_debug_company << 16, 0, CMD_COMPANY_CTRL); + break; + + case WID_AID_SETTINGS: + ShowAISettingsWindow(ai_debug_company); + break; + + case WID_AID_BREAK_STR_ON_OFF_BTN: + this->break_check_enabled = !this->break_check_enabled; + this->InvalidateData(-1); + break; + + case WID_AID_MATCH_CASE_BTN: + this->case_sensitive_break_check = !this->case_sensitive_break_check; + this->InvalidateData(-1); + break; + + case WID_AID_CONTINUE_BTN: + /* Unpause current AI / game script and mark the corresponding script button dirty. */ + if (!this->IsDead()) { + if (ai_debug_company == OWNER_DEITY) { + Game::Unpause(); + } else { + AI::Unpause(ai_debug_company); + } + } + + /* If the last AI/Game Script is unpaused, unpause the game too. */ + if ((_pause_mode & PM_PAUSED_NORMAL) == PM_PAUSED_NORMAL) { + bool all_unpaused = !Game::IsPaused(); + if (all_unpaused) { + Company *c; + FOR_ALL_COMPANIES(c) { + if (c->is_ai && AI::IsPaused(c->index)) { + all_unpaused = false; + break; + } + } + if (all_unpaused) { + /* All scripts have been unpaused => unpause the game. */ + DoCommandP(0, PM_PAUSED_NORMAL, 0, CMD_PAUSE); + } + } + } + + this->highlight_row = -1; + this->InvalidateData(-1); + break; + } + } + + virtual void OnEditboxChanged(int wid) + { + if (wid == WID_AID_BREAK_STR_EDIT_BOX) { + /* Save the current string to static member so it can be restored next time the window is opened. */ + strecpy(this->break_string, this->break_editbox.text.buf, lastof(this->break_string)); + break_string_filter.SetFilterTerm(this->break_string); + } + } + + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * This is the company ID of the AI/GS which wrote a new log message, or -1 in other cases. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + /* If the log message is related to the active company tab, check the break string. + * This needs to be done in gameloop-scope, so the AI is suspended immediately. */ + if (!gui_scope && data == ai_debug_company && this->IsValidDebugCompany(ai_debug_company) && this->break_check_enabled && !this->break_string_filter.IsEmpty()) { + /* Get the log instance of the active company */ + ScriptLog::LogData *log = this->GetLogPointer(); + + if (log != NULL) { + this->break_string_filter.ResetState(); + this->break_string_filter.AddLine(log->lines[log->pos]); + if (this->break_string_filter.GetState()) { + /* Pause execution of script. */ + if (!this->IsDead()) { + if (ai_debug_company == OWNER_DEITY) { + Game::Pause(); + } else { + AI::Pause(ai_debug_company); + } + } + + /* Pause the game. */ + if ((_pause_mode & PM_PAUSED_NORMAL) == PM_UNPAUSED) { + DoCommandP(0, PM_PAUSED_NORMAL, 1, CMD_PAUSE); + } + + /* Highlight row that matched */ + this->highlight_row = log->pos; + } + } + } + + if (!gui_scope) return; + + this->SelectValidDebugCompany(); + + ScriptLog::LogData *log = ai_debug_company != INVALID_COMPANY ? this->GetLogPointer() : NULL; + this->vscroll->SetCount((log == NULL) ? 0 : log->used); + + /* Update company buttons */ + for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) { + this->SetWidgetDisabledState(i + WID_AID_COMPANY_BUTTON_START, !Company::IsValidAiID(i)); + this->SetWidgetLoweredState(i + WID_AID_COMPANY_BUTTON_START, ai_debug_company == i); + } + + this->SetWidgetDisabledState(WID_AID_SCRIPT_GAME, Game::GetGameInstance() == NULL); + this->SetWidgetLoweredState(WID_AID_SCRIPT_GAME, ai_debug_company == OWNER_DEITY); + + this->SetWidgetLoweredState(WID_AID_BREAK_STR_ON_OFF_BTN, this->break_check_enabled); + this->SetWidgetLoweredState(WID_AID_MATCH_CASE_BTN, this->case_sensitive_break_check); + + this->SetWidgetDisabledState(WID_AID_SETTINGS, ai_debug_company == INVALID_COMPANY); + this->SetWidgetDisabledState(WID_AID_RELOAD_TOGGLE, ai_debug_company == INVALID_COMPANY || ai_debug_company == OWNER_DEITY); + this->SetWidgetDisabledState(WID_AID_CONTINUE_BTN, ai_debug_company == INVALID_COMPANY || + (ai_debug_company == OWNER_DEITY ? !Game::IsPaused() : !AI::IsPaused(ai_debug_company))); + } + + virtual void OnResize() + { + this->vscroll->SetCapacityFromWidget(this, WID_AID_LOG_PANEL); + } + + static HotkeyList hotkeys; +}; + +const int AIDebugWindow::top_offset = WD_FRAMERECT_TOP + 2; +const int AIDebugWindow::bottom_offset = WD_FRAMERECT_BOTTOM; +CompanyID AIDebugWindow::ai_debug_company = INVALID_COMPANY; +char AIDebugWindow::break_string[MAX_BREAK_STR_STRING_LENGTH] = ""; +bool AIDebugWindow::break_check_enabled = true; +bool AIDebugWindow::case_sensitive_break_check = false; +StringFilter AIDebugWindow::break_string_filter(&AIDebugWindow::case_sensitive_break_check); + +/** Make a number of rows with buttons for each company for the AI debug window. */ +NWidgetBase *MakeCompanyButtonRowsAIDebug(int *biggest_index) +{ + return MakeCompanyButtonRows(biggest_index, WID_AID_COMPANY_BUTTON_START, WID_AID_COMPANY_BUTTON_END, 8, STR_AI_DEBUG_SELECT_AI_TOOLTIP); +} + +/** + * Handler for global hotkeys of the AIDebugWindow. + * @param hotkey Hotkey + * @return ES_HANDLED if hotkey was accepted. + */ +static EventState AIDebugGlobalHotkeys(int hotkey) +{ + if (_game_mode != GM_NORMAL) return ES_NOT_HANDLED; + Window *w = ShowAIDebugWindow(INVALID_COMPANY); + if (w == NULL) return ES_NOT_HANDLED; + return w->OnHotkey(hotkey); +} + +static Hotkey aidebug_hotkeys[] = { + Hotkey('1', "company_1", WID_AID_COMPANY_BUTTON_START), + Hotkey('2', "company_2", WID_AID_COMPANY_BUTTON_START + 1), + Hotkey('3', "company_3", WID_AID_COMPANY_BUTTON_START + 2), + Hotkey('4', "company_4", WID_AID_COMPANY_BUTTON_START + 3), + Hotkey('5', "company_5", WID_AID_COMPANY_BUTTON_START + 4), + Hotkey('6', "company_6", WID_AID_COMPANY_BUTTON_START + 5), + Hotkey('7', "company_7", WID_AID_COMPANY_BUTTON_START + 6), + Hotkey('8', "company_8", WID_AID_COMPANY_BUTTON_START + 7), + Hotkey('9', "company_9", WID_AID_COMPANY_BUTTON_START + 8), + Hotkey((uint16)0, "company_10", WID_AID_COMPANY_BUTTON_START + 9), + Hotkey((uint16)0, "company_11", WID_AID_COMPANY_BUTTON_START + 10), + Hotkey((uint16)0, "company_12", WID_AID_COMPANY_BUTTON_START + 11), + Hotkey((uint16)0, "company_13", WID_AID_COMPANY_BUTTON_START + 12), + Hotkey((uint16)0, "company_14", WID_AID_COMPANY_BUTTON_START + 13), + Hotkey((uint16)0, "company_15", WID_AID_COMPANY_BUTTON_START + 14), + Hotkey('S', "settings", WID_AID_SETTINGS), + Hotkey('0', "game_script", WID_AID_SCRIPT_GAME), + Hotkey((uint16)0, "reload", WID_AID_RELOAD_TOGGLE), + Hotkey('B', "break_toggle", WID_AID_BREAK_STR_ON_OFF_BTN), + Hotkey('F', "break_string", WID_AID_BREAK_STR_EDIT_BOX), + Hotkey('C', "match_case", WID_AID_MATCH_CASE_BTN), + Hotkey(WKC_RETURN, "continue", WID_AID_CONTINUE_BTN), + HOTKEY_LIST_END +}; +HotkeyList AIDebugWindow::hotkeys("aidebug", aidebug_hotkeys, AIDebugGlobalHotkeys); + +/** Widgets for the AI debug window. */ +static const NWidgetPart _nested_ai_debug_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_AI_DEBUG, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), + NWidget(WWT_STICKYBOX, COLOUR_GREY), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_AID_VIEW), + NWidgetFunction(MakeCompanyButtonRowsAIDebug), SetPadding(0, 2, 1, 2), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AID_SCRIPT_GAME), SetMinimalSize(100, 20), SetResize(1, 0), SetDataTip(STR_AI_GAME_SCRIPT, STR_AI_GAME_SCRIPT_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AID_NAME_TEXT), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_JUST_STRING, STR_AI_DEBUG_NAME_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_AID_SETTINGS), SetMinimalSize(100, 20), SetDataTip(STR_AI_DEBUG_SETTINGS, STR_AI_DEBUG_SETTINGS_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_AID_RELOAD_TOGGLE), SetMinimalSize(100, 20), SetDataTip(STR_AI_DEBUG_RELOAD, STR_AI_DEBUG_RELOAD_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_VERTICAL), + /* Log panel */ + NWidget(WWT_PANEL, COLOUR_GREY, WID_AID_LOG_PANEL), SetMinimalSize(287, 180), SetResize(1, 1), SetScrollbar(WID_AID_SCROLLBAR), + EndContainer(), + /* Break string widgets */ + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_AID_BREAK_STRING_WIDGETS), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_IMGBTN_2, COLOUR_GREY, WID_AID_BREAK_STR_ON_OFF_BTN), SetFill(0, 1), SetDataTip(SPR_FLAG_VEH_STOPPED, STR_AI_DEBUG_BREAK_STR_ON_OFF_TOOLTIP), + NWidget(WWT_PANEL, COLOUR_GREY), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_LABEL, COLOUR_GREY), SetPadding(2, 2, 2, 4), SetDataTip(STR_AI_DEBUG_BREAK_ON_LABEL, 0x0), + NWidget(WWT_EDITBOX, COLOUR_GREY, WID_AID_BREAK_STR_EDIT_BOX), SetFill(1, 1), SetResize(1, 0), SetPadding(2, 2, 2, 2), SetDataTip(STR_AI_DEBUG_BREAK_STR_OSKTITLE, STR_AI_DEBUG_BREAK_STR_TOOLTIP), + EndContainer(), + EndContainer(), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AID_MATCH_CASE_BTN), SetMinimalSize(100, 0), SetFill(0, 1), SetDataTip(STR_AI_DEBUG_MATCH_CASE, STR_AI_DEBUG_MATCH_CASE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_AID_CONTINUE_BTN), SetMinimalSize(100, 0), SetFill(0, 1), SetDataTip(STR_AI_DEBUG_CONTINUE, STR_AI_DEBUG_CONTINUE_TOOLTIP), + EndContainer(), + EndContainer(), + EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_AID_SCROLLBAR), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), + EndContainer(), +}; + +/** Window definition for the AI debug window. */ +static WindowDesc _ai_debug_desc( + WDP_AUTO, "script_debug", 600, 450, + WC_AI_DEBUG, WC_NONE, + 0, + _nested_ai_debug_widgets, lengthof(_nested_ai_debug_widgets), + &AIDebugWindow::hotkeys +); + +/** + * Open the AI debug window and select the given company. + * @param show_company Display debug information about this AI company. + */ +Window *ShowAIDebugWindow(CompanyID show_company) +{ + if (!_networking || _network_server) { + AIDebugWindow *w = (AIDebugWindow *)BringWindowToFrontById(WC_AI_DEBUG, 0); + if (w == NULL) w = new AIDebugWindow(&_ai_debug_desc, 0); + if (show_company != INVALID_COMPANY) w->ChangeToAI(show_company); + return w; + } else { + ShowErrorMessage(STR_ERROR_AI_DEBUG_SERVER_ONLY, INVALID_STRING_ID, WL_INFO); + } + + return NULL; +} + +/** + * Reset the AI windows to their initial state. + */ +void InitializeAIGui() +{ + AIDebugWindow::ai_debug_company = INVALID_COMPANY; +} + +/** Open the AI debug window if one of the AI scripts has crashed. */ +void ShowAIDebugWindowIfAIError() +{ + /* Network clients can't debug AIs. */ + if (_networking && !_network_server) return; + + Company *c; + FOR_ALL_COMPANIES(c) { + if (c->is_ai && c->ai_instance->IsDead()) { + ShowAIDebugWindow(c->index); + break; + } + } + + GameInstance *g = Game::GetGameInstance(); + if (g != NULL && g->IsDead()) { + ShowAIDebugWindow(OWNER_DEITY); + } +} diff --git a/src/ai/ai_gui.hpp b/src/ai/ai_gui.hpp new file mode 100644 index 0000000..ad6eed8 --- /dev/null +++ b/src/ai/ai_gui.hpp @@ -0,0 +1,22 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file ai_gui.hpp %Window for configuring the AIs */ + +#ifndef AI_GUI_HPP +#define AI_GUI_HPP + +#include "../company_type.h" + +Window* ShowAIDebugWindow(CompanyID show_company = INVALID_COMPANY); +void ShowAIConfigWindow(); +void ShowAIDebugWindowIfAIError(); +void InitializeAIGui(); + +#endif /* AI_GUI_HPP */ diff --git a/src/ai/ai_info.cpp b/src/ai/ai_info.cpp new file mode 100644 index 0000000..017a168 --- /dev/null +++ b/src/ai/ai_info.cpp @@ -0,0 +1,183 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file ai_info.cpp Implementation of AIInfo and AILibrary */ + +#include "../stdafx.h" + +#include "../script/squirrel_class.hpp" +#include "ai_info.hpp" +#include "ai_scanner.hpp" +#include "../debug.h" +#include "../string_func.h" +#include "../rev.h" + +#include "../safeguards.h" + +/** + * Check if the API version provided by the AI is supported. + * @param api_version The API version as provided by the AI. + */ +static bool CheckAPIVersion(const char *api_version) +{ + return strcmp(api_version, "0.7") == 0 || strcmp(api_version, "1.0") == 0 || strcmp(api_version, "1.1") == 0 || + strcmp(api_version, "1.2") == 0 || strcmp(api_version, "1.3") == 0 || strcmp(api_version, "1.4") == 0 || + strcmp(api_version, "1.5") == 0; +} + +#if defined(WIN32) +#undef GetClassName +#endif /* WIN32 */ +template <> const char *GetClassName() { return "AIInfo"; } + +/* static */ void AIInfo::RegisterAPI(Squirrel *engine) +{ + /* Create the AIInfo class, and add the RegisterAI function */ + DefSQClass SQAIInfo("AIInfo"); + SQAIInfo.PreRegister(engine); + SQAIInfo.AddConstructor(engine, "x"); + SQAIInfo.DefSQAdvancedMethod(engine, &AIInfo::AddSetting, "AddSetting"); + SQAIInfo.DefSQAdvancedMethod(engine, &AIInfo::AddLabels, "AddLabels"); + SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_NONE, "CONFIG_NONE"); + SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_RANDOM, "CONFIG_RANDOM"); + SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_BOOLEAN, "CONFIG_BOOLEAN"); + SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_INGAME, "CONFIG_INGAME"); + SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_DEVELOPER, "CONFIG_DEVELOPER"); + + /* Pre 1.2 had an AI prefix */ + SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_NONE, "AICONFIG_NONE"); + SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_RANDOM, "AICONFIG_RANDOM"); + SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_BOOLEAN, "AICONFIG_BOOLEAN"); + SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_INGAME, "AICONFIG_INGAME"); + + SQAIInfo.PostRegister(engine); + engine->AddMethod("RegisterAI", &AIInfo::Constructor, 2, "tx"); + engine->AddMethod("RegisterDummyAI", &AIInfo::DummyConstructor, 2, "tx"); +} + +/* static */ SQInteger AIInfo::Constructor(HSQUIRRELVM vm) +{ + /* Get the AIInfo */ + SQUserPointer instance = NULL; + if (SQ_FAILED(sq_getinstanceup(vm, 2, &instance, 0)) || instance == NULL) return sq_throwerror(vm, "Pass an instance of a child class of AIInfo to RegisterAI"); + AIInfo *info = (AIInfo *)instance; + + SQInteger res = ScriptInfo::Constructor(vm, info); + if (res != 0) return res; + + ScriptConfigItem config = _start_date_config; + config.name = stredup(config.name); + config.description = stredup(config.description); + info->config_list.push_front(config); + + if (info->engine->MethodExists(*info->SQ_instance, "MinVersionToLoad")) { + if (!info->engine->CallIntegerMethod(*info->SQ_instance, "MinVersionToLoad", &info->min_loadable_version, MAX_GET_OPS)) return SQ_ERROR; + } else { + info->min_loadable_version = info->GetVersion(); + } + /* When there is an UseAsRandomAI function, call it. */ + if (info->engine->MethodExists(*info->SQ_instance, "UseAsRandomAI")) { + if (!info->engine->CallBoolMethod(*info->SQ_instance, "UseAsRandomAI", &info->use_as_random, MAX_GET_OPS)) return SQ_ERROR; + } else { + info->use_as_random = true; + } + /* Try to get the API version the AI is written for. */ + if (info->engine->MethodExists(*info->SQ_instance, "GetAPIVersion")) { + if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetAPIVersion", &info->api_version, MAX_GET_OPS)) return SQ_ERROR; + if (!CheckAPIVersion(info->api_version)) { + DEBUG(script, 1, "Loading info.nut from (%s.%d): GetAPIVersion returned invalid version", info->GetName(), info->GetVersion()); + return SQ_ERROR; + } + } else { + info->api_version = stredup("0.7"); + } + + /* Remove the link to the real instance, else it might get deleted by RegisterAI() */ + sq_setinstanceup(vm, 2, NULL); + /* Register the AI to the base system */ + info->GetScanner()->RegisterScript(info); + return 0; +} + +/* static */ SQInteger AIInfo::DummyConstructor(HSQUIRRELVM vm) +{ + /* Get the AIInfo */ + SQUserPointer instance; + sq_getinstanceup(vm, 2, &instance, 0); + AIInfo *info = (AIInfo *)instance; + info->api_version = NULL; + + SQInteger res = ScriptInfo::Constructor(vm, info); + if (res != 0) return res; + + char buf[8]; + seprintf(buf, lastof(buf), "%d.%d", GB(_openttd_newgrf_version, 28, 4), GB(_openttd_newgrf_version, 24, 4)); + info->api_version = stredup(buf); + + /* Remove the link to the real instance, else it might get deleted by RegisterAI() */ + sq_setinstanceup(vm, 2, NULL); + /* Register the AI to the base system */ + static_cast(info->GetScanner())->SetDummyAI(info); + return 0; +} + +AIInfo::AIInfo() : + min_loadable_version(0), + use_as_random(false), + api_version(NULL) +{ +} + +AIInfo::~AIInfo() +{ + free(this->api_version); +} + +bool AIInfo::CanLoadFromVersion(int version) const +{ + if (version == -1) return true; + return version >= this->min_loadable_version && version <= this->GetVersion(); +} + + +AILibrary::~AILibrary() +{ + free(this->category); +} + +/* static */ void AILibrary::RegisterAPI(Squirrel *engine) +{ + /* Create the AILibrary class, and add the RegisterLibrary function */ + engine->AddClassBegin("AILibrary"); + engine->AddClassEnd(); + engine->AddMethod("RegisterLibrary", &AILibrary::Constructor, 2, "tx"); +} + +/* static */ SQInteger AILibrary::Constructor(HSQUIRRELVM vm) +{ + /* Create a new library */ + AILibrary *library = new AILibrary(); + + SQInteger res = ScriptInfo::Constructor(vm, library); + if (res != 0) { + delete library; + return res; + } + + /* Cache the category */ + if (!library->CheckMethod("GetCategory") || !library->engine->CallStringMethodStrdup(*library->SQ_instance, "GetCategory", &library->category, MAX_GET_OPS)) { + delete library; + return SQ_ERROR; + } + + /* Register the Library to the base system */ + library->GetScanner()->RegisterScript(library); + + return 0; +} diff --git a/src/ai/ai_info.hpp b/src/ai/ai_info.hpp new file mode 100644 index 0000000..51cfb7d --- /dev/null +++ b/src/ai/ai_info.hpp @@ -0,0 +1,84 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file ai_info.hpp AIInfo keeps track of all information of an AI, like Author, Description, ... */ + +#ifndef AI_INFO_HPP +#define AI_INFO_HPP + +#include "../script/script_info.hpp" + +/** All static information from an AI like name, version, etc. */ +class AIInfo : public ScriptInfo { +public: + AIInfo(); + ~AIInfo(); + + /** + * Register the functions of this class. + */ + static void RegisterAPI(Squirrel *engine); + + /** + * Create an AI, using this AIInfo as start-template. + */ + static SQInteger Constructor(HSQUIRRELVM vm); + + /** + * Create a dummy-AI. + */ + static SQInteger DummyConstructor(HSQUIRRELVM vm); + + /** + * Check if we can start this AI. + */ + bool CanLoadFromVersion(int version) const; + + /** + * Use this AI as a random AI. + */ + bool UseAsRandomAI() const { return this->use_as_random; } + + /** + * Get the API version this AI is written for. + */ + const char *GetAPIVersion() const { return this->api_version; } + +private: + int min_loadable_version; ///< The AI can load savegame data if the version is equal or greater than this. + bool use_as_random; ///< Should this AI be used when the user wants a "random AI"? + const char *api_version; ///< API version used by this AI. +}; + +/** All static information from an AI library like name, version, etc. */ +class AILibrary : public ScriptInfo { +public: + AILibrary() : ScriptInfo(), category(NULL) {}; + ~AILibrary(); + + /** + * Register the functions of this class. + */ + static void RegisterAPI(Squirrel *engine); + + /** + * Create an AI, using this AIInfo as start-template. + */ + static SQInteger Constructor(HSQUIRRELVM vm); + + /** + * Get the category this library is in. + */ + const char *GetCategory() const { return this->category; } + +private: + const char *category; ///< The category this library is in. +}; + +#endif /* AI_INFO_HPP */ diff --git a/src/ai/ai_instance.cpp b/src/ai/ai_instance.cpp new file mode 100644 index 0000000..c03e745 --- /dev/null +++ b/src/ai/ai_instance.cpp @@ -0,0 +1,270 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file ai_instance.cpp Implementation of AIInstance. */ + +#include "../stdafx.h" +#include "../debug.h" +#include "../error.h" + +#include "../script/squirrel_class.hpp" + +#include "ai_config.hpp" +#include "ai_gui.hpp" +#include "ai.hpp" + +#include "../script/script_storage.hpp" +#include "ai_info.hpp" +#include "ai_instance.hpp" + +/* Manually include the Text glue. */ +#include "../script/api/template/template_text.hpp.sq" + +/* Convert all AI related classes to Squirrel data. + * Note: this line is a marker in squirrel_export.sh. Do not change! */ +#include "../script/api/ai/ai_accounting.hpp.sq" +#include "../script/api/ai/ai_airport.hpp.sq" +#include "../script/api/ai/ai_base.hpp.sq" +#include "../script/api/ai/ai_basestation.hpp.sq" +#include "../script/api/ai/ai_bridge.hpp.sq" +#include "../script/api/ai/ai_bridgelist.hpp.sq" +#include "../script/api/ai/ai_cargo.hpp.sq" +#include "../script/api/ai/ai_cargolist.hpp.sq" +#include "../script/api/ai/ai_company.hpp.sq" +#include "../script/api/ai/ai_controller.hpp.sq" +#include "../script/api/ai/ai_date.hpp.sq" +#include "../script/api/ai/ai_depotlist.hpp.sq" +#include "../script/api/ai/ai_engine.hpp.sq" +#include "../script/api/ai/ai_enginelist.hpp.sq" +#include "../script/api/ai/ai_error.hpp.sq" +#include "../script/api/ai/ai_event.hpp.sq" +#include "../script/api/ai/ai_event_types.hpp.sq" +#include "../script/api/ai/ai_execmode.hpp.sq" +#include "../script/api/ai/ai_gamesettings.hpp.sq" +#include "../script/api/ai/ai_group.hpp.sq" +#include "../script/api/ai/ai_grouplist.hpp.sq" +#include "../script/api/ai/ai_industry.hpp.sq" +#include "../script/api/ai/ai_industrylist.hpp.sq" +#include "../script/api/ai/ai_industrytype.hpp.sq" +#include "../script/api/ai/ai_industrytypelist.hpp.sq" +#include "../script/api/ai/ai_infrastructure.hpp.sq" +#include "../script/api/ai/ai_list.hpp.sq" +#include "../script/api/ai/ai_log.hpp.sq" +#include "../script/api/ai/ai_map.hpp.sq" +#include "../script/api/ai/ai_marine.hpp.sq" +#include "../script/api/ai/ai_order.hpp.sq" +#include "../script/api/ai/ai_rail.hpp.sq" +#include "../script/api/ai/ai_railtypelist.hpp.sq" +#include "../script/api/ai/ai_road.hpp.sq" +#include "../script/api/ai/ai_sign.hpp.sq" +#include "../script/api/ai/ai_signlist.hpp.sq" +#include "../script/api/ai/ai_station.hpp.sq" +#include "../script/api/ai/ai_stationlist.hpp.sq" +#include "../script/api/ai/ai_subsidy.hpp.sq" +#include "../script/api/ai/ai_subsidylist.hpp.sq" +#include "../script/api/ai/ai_testmode.hpp.sq" +#include "../script/api/ai/ai_tile.hpp.sq" +#include "../script/api/ai/ai_tilelist.hpp.sq" +#include "../script/api/ai/ai_town.hpp.sq" +#include "../script/api/ai/ai_townlist.hpp.sq" +#include "../script/api/ai/ai_tunnel.hpp.sq" +#include "../script/api/ai/ai_vehicle.hpp.sq" +#include "../script/api/ai/ai_vehiclelist.hpp.sq" +#include "../script/api/ai/ai_waypoint.hpp.sq" +#include "../script/api/ai/ai_waypointlist.hpp.sq" + +#include "../company_base.h" +#include "../company_func.h" + +#include "../safeguards.h" + +AIInstance::AIInstance() : + ScriptInstance("AI") +{} + +void AIInstance::Initialize(AIInfo *info) +{ + this->versionAPI = info->GetAPIVersion(); + + /* Register the AIController (including the "import" command) */ + SQAIController_Register(this->engine); + + ScriptInstance::Initialize(info->GetMainScript(), info->GetInstanceName(), _current_company); +} + +void AIInstance::RegisterAPI() +{ + ScriptInstance::RegisterAPI(); + +/* Register all classes */ + SQAIList_Register(this->engine); + SQAIAccounting_Register(this->engine); + SQAIAirport_Register(this->engine); + SQAIBase_Register(this->engine); + SQAIBaseStation_Register(this->engine); + SQAIBridge_Register(this->engine); + SQAIBridgeList_Register(this->engine); + SQAIBridgeList_Length_Register(this->engine); + SQAICargo_Register(this->engine); + SQAICargoList_Register(this->engine); + SQAICargoList_IndustryAccepting_Register(this->engine); + SQAICargoList_IndustryProducing_Register(this->engine); + SQAICargoList_StationAccepting_Register(this->engine); + SQAICompany_Register(this->engine); + SQAIDate_Register(this->engine); + SQAIDepotList_Register(this->engine); + SQAIEngine_Register(this->engine); + SQAIEngineList_Register(this->engine); + SQAIError_Register(this->engine); + SQAIEvent_Register(this->engine); + SQAIEventAircraftDestTooFar_Register(this->engine); + SQAIEventCompanyAskMerger_Register(this->engine); + SQAIEventCompanyBankrupt_Register(this->engine); + SQAIEventCompanyInTrouble_Register(this->engine); + SQAIEventCompanyMerger_Register(this->engine); + SQAIEventCompanyNew_Register(this->engine); + SQAIEventCompanyTown_Register(this->engine); + SQAIEventController_Register(this->engine); + SQAIEventDisasterZeppelinerCleared_Register(this->engine); + SQAIEventDisasterZeppelinerCrashed_Register(this->engine); + SQAIEventEngineAvailable_Register(this->engine); + SQAIEventEnginePreview_Register(this->engine); + SQAIEventExclusiveTransportRights_Register(this->engine); + SQAIEventIndustryClose_Register(this->engine); + SQAIEventIndustryOpen_Register(this->engine); + SQAIEventRoadReconstruction_Register(this->engine); + SQAIEventStationFirstVehicle_Register(this->engine); + SQAIEventSubsidyAwarded_Register(this->engine); + SQAIEventSubsidyExpired_Register(this->engine); + SQAIEventSubsidyOffer_Register(this->engine); + SQAIEventSubsidyOfferExpired_Register(this->engine); + SQAIEventTownFounded_Register(this->engine); + SQAIEventVehicleCrashed_Register(this->engine); + SQAIEventVehicleLost_Register(this->engine); + SQAIEventVehicleUnprofitable_Register(this->engine); + SQAIEventVehicleWaitingInDepot_Register(this->engine); + SQAIExecMode_Register(this->engine); + SQAIGameSettings_Register(this->engine); + SQAIGroup_Register(this->engine); + SQAIGroupList_Register(this->engine); + SQAIIndustry_Register(this->engine); + SQAIIndustryList_Register(this->engine); + SQAIIndustryList_CargoAccepting_Register(this->engine); + SQAIIndustryList_CargoProducing_Register(this->engine); + SQAIIndustryType_Register(this->engine); + SQAIIndustryTypeList_Register(this->engine); + SQAIInfrastructure_Register(this->engine); + SQAILog_Register(this->engine); + SQAIMap_Register(this->engine); + SQAIMarine_Register(this->engine); + SQAIOrder_Register(this->engine); + SQAIRail_Register(this->engine); + SQAIRailTypeList_Register(this->engine); + SQAIRoad_Register(this->engine); + SQAISign_Register(this->engine); + SQAISignList_Register(this->engine); + SQAIStation_Register(this->engine); + SQAIStationList_Register(this->engine); + SQAIStationList_Cargo_Register(this->engine); + SQAIStationList_CargoPlanned_Register(this->engine); + SQAIStationList_CargoPlannedByFrom_Register(this->engine); + SQAIStationList_CargoPlannedByVia_Register(this->engine); + SQAIStationList_CargoPlannedFromByVia_Register(this->engine); + SQAIStationList_CargoPlannedViaByFrom_Register(this->engine); + SQAIStationList_CargoWaiting_Register(this->engine); + SQAIStationList_CargoWaitingByFrom_Register(this->engine); + SQAIStationList_CargoWaitingByVia_Register(this->engine); + SQAIStationList_CargoWaitingFromByVia_Register(this->engine); + SQAIStationList_CargoWaitingViaByFrom_Register(this->engine); + SQAIStationList_Vehicle_Register(this->engine); + SQAISubsidy_Register(this->engine); + SQAISubsidyList_Register(this->engine); + SQAITestMode_Register(this->engine); + SQAITile_Register(this->engine); + SQAITileList_Register(this->engine); + SQAITileList_IndustryAccepting_Register(this->engine); + SQAITileList_IndustryProducing_Register(this->engine); + SQAITileList_StationType_Register(this->engine); + SQAITown_Register(this->engine); + SQAITownEffectList_Register(this->engine); + SQAITownList_Register(this->engine); + SQAITunnel_Register(this->engine); + SQAIVehicle_Register(this->engine); + SQAIVehicleList_Register(this->engine); + SQAIVehicleList_DefaultGroup_Register(this->engine); + SQAIVehicleList_Depot_Register(this->engine); + SQAIVehicleList_Group_Register(this->engine); + SQAIVehicleList_SharedOrders_Register(this->engine); + SQAIVehicleList_Station_Register(this->engine); + SQAIWaypoint_Register(this->engine); + SQAIWaypointList_Register(this->engine); + SQAIWaypointList_Vehicle_Register(this->engine); + + if (!this->LoadCompatibilityScripts(this->versionAPI, AI_DIR)) this->Died(); +} + +void AIInstance::Died() +{ + ScriptInstance::Died(); + + ShowAIDebugWindow(_current_company); + + const AIInfo *info = AIConfig::GetConfig(_current_company, AIConfig::SSS_FORCE_GAME)->GetInfo(); + if (info != NULL) { + ShowErrorMessage(STR_ERROR_AI_PLEASE_REPORT_CRASH, INVALID_STRING_ID, WL_WARNING); + + if (info->GetURL() != NULL) { + ScriptLog::Info("Please report the error to the following URL:"); + ScriptLog::Info(info->GetURL()); + } + } +} + +void AIInstance::LoadDummyScript() +{ + extern void Script_CreateDummy(HSQUIRRELVM vm, StringID string, const char *type); + Script_CreateDummy(this->engine->GetVM(), STR_ERROR_AI_NO_AI_FOUND, "AI"); +} + +int AIInstance::GetSetting(const char *name) +{ + return AIConfig::GetConfig(_current_company)->GetSetting(name); +} + +ScriptInfo *AIInstance::FindLibrary(const char *library, int version) +{ + return (ScriptInfo *)AI::FindLibrary(library, version); +} + +/** + * DoCommand callback function for all commands executed by AIs. + * @param result The result of the command. + * @param tile The tile on which the command was executed. + * @param p1 p1 as given to DoCommandPInternal. + * @param p2 p2 as given to DoCommandPInternal. + */ +void CcAI(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) +{ + /* + * The company might not exist anymore. Check for this. + * The command checks are not useful since this callback + * is also called when the command fails, which is does + * when the company does not exist anymore. + */ + const Company *c = Company::GetIfValid(_current_company); + if (c == NULL || c->ai_instance == NULL) return; + + c->ai_instance->DoCommandCallback(result, tile, p1, p2); + c->ai_instance->Continue(); +} + +CommandCallback *AIInstance::GetDoCommandCallback() +{ + return &CcAI; +} diff --git a/src/ai/ai_instance.hpp b/src/ai/ai_instance.hpp new file mode 100644 index 0000000..204bf97 --- /dev/null +++ b/src/ai/ai_instance.hpp @@ -0,0 +1,38 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file ai_instance.hpp The AIInstance tracks an AI. */ + +#ifndef AI_INSTANCE_HPP +#define AI_INSTANCE_HPP + +#include "../script/script_instance.hpp" + +/** Runtime information about an AI like a pointer to the squirrel vm and the current state. */ +class AIInstance : public ScriptInstance { +public: + AIInstance(); + + /** + * Initialize the AI and prepare it for its first run. + * @param info The AI to create the instance of. + */ + void Initialize(class AIInfo *info); + + /* virtual */ int GetSetting(const char *name); + /* virtual */ ScriptInfo *FindLibrary(const char *library, int version); + +private: + /* virtual */ void RegisterAPI(); + /* virtual */ void Died(); + /* virtual */ CommandCallback *GetDoCommandCallback(); + /* virtual */ void LoadDummyScript(); +}; + +#endif /* AI_INSTANCE_HPP */ diff --git a/src/ai/ai_scanner.cpp b/src/ai/ai_scanner.cpp new file mode 100644 index 0000000..4eb2071 --- /dev/null +++ b/src/ai/ai_scanner.cpp @@ -0,0 +1,171 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file ai_scanner.cpp allows scanning AI scripts */ + +#include "../stdafx.h" +#include "../debug.h" +#include "../network/network.h" +#include "../core/random_func.hpp" + +#include "../script/squirrel_class.hpp" +#include "ai_info.hpp" +#include "ai_scanner.hpp" + +#include "../safeguards.h" + + +AIScannerInfo::AIScannerInfo() : + ScriptScanner(), + info_dummy(NULL) +{ +} + +void AIScannerInfo::Initialize() +{ + ScriptScanner::Initialize("AIScanner"); + + /* Create the dummy AI */ + free(this->main_script); + this->main_script = stredup("%_dummy"); + extern void Script_CreateDummyInfo(HSQUIRRELVM vm, const char *type, const char *dir); + Script_CreateDummyInfo(this->engine->GetVM(), "AI", "ai"); +} + +void AIScannerInfo::SetDummyAI(class AIInfo *info) +{ + this->info_dummy = info; +} + +AIScannerInfo::~AIScannerInfo() +{ + delete this->info_dummy; +} + +void AIScannerInfo::GetScriptName(ScriptInfo *info, char *name, const char *last) +{ + seprintf(name, last, "%s", info->GetName()); +} + +void AIScannerInfo::RegisterAPI(class Squirrel *engine) +{ + AIInfo::RegisterAPI(engine); +} + +AIInfo *AIScannerInfo::SelectRandomAI() const +{ + uint num_random_ais = 0; + for (ScriptInfoList::const_iterator it = this->info_single_list.begin(); it != this->info_single_list.end(); it++) { + AIInfo *i = static_cast((*it).second); + if (i->UseAsRandomAI()) num_random_ais++; + } + + if (num_random_ais == 0) { + DEBUG(script, 0, "No suitable AI found, loading 'dummy' AI."); + return this->info_dummy; + } + + /* Find a random AI */ + uint pos; + if (_networking) { + pos = InteractiveRandomRange(num_random_ais); + } else { + pos = RandomRange(num_random_ais); + } + + /* Find the Nth item from the array */ + ScriptInfoList::const_iterator it = this->info_single_list.begin(); + +#define GetAIInfo(it) static_cast((*it).second) + while (!GetAIInfo(it)->UseAsRandomAI()) it++; + for (; pos > 0; pos--) { + it++; + while (!GetAIInfo(it)->UseAsRandomAI()) it++; + } + return GetAIInfo(it); +#undef GetAIInfo +} + +AIInfo *AIScannerInfo::FindInfo(const char *nameParam, int versionParam, bool force_exact_match) +{ + if (this->info_list.size() == 0) return NULL; + if (nameParam == NULL) return NULL; + + char ai_name[1024]; + strecpy(ai_name, nameParam, lastof(ai_name)); + strtolower(ai_name); + + AIInfo *info = NULL; + int version = -1; + + if (versionParam == -1) { + /* We want to load the latest version of this AI; so find it */ + if (this->info_single_list.find(ai_name) != this->info_single_list.end()) return static_cast(this->info_single_list[ai_name]); + + /* If we didn't find a match AI, maybe the user included a version */ + char *e = strrchr(ai_name, '.'); + if (e == NULL) return NULL; + *e = '\0'; + e++; + versionParam = atoi(e); + /* FALL THROUGH, like we were calling this function with a version. */ + } + + if (force_exact_match) { + /* Try to find a direct 'name.version' match */ + char ai_name_tmp[1024]; + seprintf(ai_name_tmp, lastof(ai_name_tmp), "%s.%d", ai_name, versionParam); + strtolower(ai_name_tmp); + if (this->info_list.find(ai_name_tmp) != this->info_list.end()) return static_cast(this->info_list[ai_name_tmp]); + } + + /* See if there is a compatible AI which goes by that name, with the highest + * version which allows loading the requested version */ + ScriptInfoList::iterator it = this->info_list.begin(); + for (; it != this->info_list.end(); it++) { + AIInfo *i = static_cast((*it).second); + if (strcasecmp(ai_name, i->GetName()) == 0 && i->CanLoadFromVersion(versionParam) && (version == -1 || i->GetVersion() > version)) { + version = (*it).second->GetVersion(); + info = i; + } + } + + return info; +} + + +void AIScannerLibrary::Initialize() +{ + ScriptScanner::Initialize("AIScanner"); +} + +void AIScannerLibrary::GetScriptName(ScriptInfo *info, char *name, const char *last) +{ + AILibrary *library = static_cast(info); + seprintf(name, last, "%s.%s", library->GetCategory(), library->GetInstanceName()); +} + +void AIScannerLibrary::RegisterAPI(class Squirrel *engine) +{ + AILibrary::RegisterAPI(engine); +} + +AILibrary *AIScannerLibrary::FindLibrary(const char *library, int version) +{ + /* Internally we store libraries as 'library.version' */ + char library_name[1024]; + seprintf(library_name, lastof(library_name), "%s.%d", library, version); + strtolower(library_name); + + /* Check if the library + version exists */ + ScriptInfoList::iterator iter = this->info_list.find(library_name); + if (iter == this->info_list.end()) return NULL; + + return static_cast((*iter).second); +} diff --git a/src/ai/ai_scanner.hpp b/src/ai/ai_scanner.hpp new file mode 100644 index 0000000..d8e8a69 --- /dev/null +++ b/src/ai/ai_scanner.hpp @@ -0,0 +1,75 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file ai_scanner.hpp declarations of the class for AI scanner */ + +#ifndef AI_SCANNER_HPP +#define AI_SCANNER_HPP + +#include "../script/script_scanner.hpp" + +class AIScannerInfo : public ScriptScanner { +public: + AIScannerInfo(); + ~AIScannerInfo(); + + /* virtual */ void Initialize(); + + /** + * Select a random AI. + * @return A random AI from the pool. + */ + class AIInfo *SelectRandomAI() const; + + /** + * Check if we have an AI by name and version available in our list. + * @param nameParam The name of the AI. + * @param versionParam The version of the AI, or -1 if you want the latest. + * @param force_exact_match Only match name+version, never latest. + * @return NULL if no match found, otherwise the AI that matched. + */ + class AIInfo *FindInfo(const char *nameParam, int versionParam, bool force_exact_match); + + /** + * Set the Dummy AI. + */ + void SetDummyAI(class AIInfo *info); + +protected: + /* virtual */ void GetScriptName(ScriptInfo *info, char *name, const char *last); + /* virtual */ const char *GetFileName() const { return PATHSEP "info.nut"; } + /* virtual */ Subdirectory GetDirectory() const { return AI_DIR; } + /* virtual */ const char *GetScannerName() const { return "AIs"; } + /* virtual */ void RegisterAPI(class Squirrel *engine); + +private: + AIInfo *info_dummy; ///< The dummy AI. +}; + +class AIScannerLibrary : public ScriptScanner { +public: + /* virtual */ void Initialize(); + + /** + * Find a library in the pool. + * @param library The library name to find. + * @param version The version the library should have. + * @return The library if found, NULL otherwise. + */ + class AILibrary *FindLibrary(const char *library, int version); + +protected: + /* virtual */ void GetScriptName(ScriptInfo *info, char *name, const char *last); + /* virtual */ const char *GetFileName() const { return PATHSEP "library.nut"; } + /* virtual */ Subdirectory GetDirectory() const { return AI_LIBRARY_DIR; } + /* virtual */ const char *GetScannerName() const { return "AI Libraries"; } + /* virtual */ void RegisterAPI(class Squirrel *engine); +}; + +#endif /* AI_SCANNER_HPP */ diff --git a/src/aircraft.h b/src/aircraft.h new file mode 100644 index 0000000..0805ae8 --- /dev/null +++ b/src/aircraft.h @@ -0,0 +1,148 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file aircraft.h Base for aircraft. */ + +#ifndef AIRCRAFT_H +#define AIRCRAFT_H + +#include "station_map.h" +#include "vehicle_base.h" + +/** + * Base values for flight levels above ground level for 'normal' flight and holding patterns. + * Due to speed and direction, the actual flight level may be higher. + */ +enum AircraftFlyingAltitude { + AIRCRAFT_MIN_FLYING_ALTITUDE = 120, ///< Minimum flying altitude above tile. + AIRCRAFT_MAX_FLYING_ALTITUDE = 360, ///< Maximum flying altitude above tile. + PLANE_HOLD_MAX_FLYING_ALTITUDE = 150, ///< holding flying altitude above tile of planes. + HELICOPTER_HOLD_MAX_FLYING_ALTITUDE = 184 ///< holding flying altitude above tile of helicopters. +}; + +struct Aircraft; + +/** An aircraft can be one of those types. */ +enum AircraftSubType { + AIR_HELICOPTER = 0, ///< an helicopter + AIR_AIRCRAFT = 2, ///< an airplane + AIR_SHADOW = 4, ///< shadow of the aircraft + AIR_ROTOR = 6, ///< rotor of an helicopter +}; + +/** Flags for air vehicles; shared with disaster vehicles. */ +enum AirVehicleFlags { + VAF_DEST_TOO_FAR = 0, ///< Next destination is too far away. + + /* The next two flags are to prevent stair climbing of the aircraft. The idea is that the aircraft + * will ascend or descend multiple flight levels at a time instead of following the contours of the + * landscape at a fixed altitude. This only has effect when there are more than 15 height levels. */ + VAF_IN_MAX_HEIGHT_CORRECTION = 1, ///< The vehicle is currently lowering its altitude because it hit the upper bound. + VAF_IN_MIN_HEIGHT_CORRECTION = 2, ///< The vehicle is currently raising its altitude because it hit the lower bound. +}; + +static const int ROTOR_Z_OFFSET = 5; ///< Z Offset between helicopter- and rotorsprite. + +void HandleAircraftEnterHangar(Aircraft *v); +void GetAircraftSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type); +void UpdateAirplanesOnNewStation(const Station *st); +void UpdateAircraftCache(Aircraft *v, bool update_range = false); + +void AircraftLeaveHangar(Aircraft *v, Direction exit_dir); +void AircraftNextAirportPos_and_Order(Aircraft *v); +void SetAircraftPosition(Aircraft *v, int x, int y, int z); + +void GetAircraftFlightLevelBounds(const Vehicle *v, int *min, int *max); +template +int GetAircraftFlightLevel(T *v, bool takeoff = false); + +/** Variables that are cached to improve performance and such. */ +struct AircraftCache { + uint32 cached_max_range_sqr; ///< Cached squared maximum range. + uint16 cached_max_range; ///< Cached maximum range. +}; + +/** + * Aircraft, helicopters, rotors and their shadows belong to this class. + */ +struct Aircraft FINAL : public SpecializedVehicle { + uint16 crashed_counter; ///< Timer for handling crash animations. + byte pos; ///< Next desired position of the aircraft. + byte previous_pos; ///< Previous desired position of the aircraft. + StationID targetairport; ///< Airport to go to next. + byte state; ///< State of the airport. @see AirportMovementStates + DirectionByte last_direction; + byte number_consecutive_turns; ///< Protection to prevent the aircraft of making a lot of turns in order to reach a specific point. + byte turn_counter; ///< Ticks between each turn to prevent > 45 degree turns. + byte flags; ///< Aircraft flags. @see AirVehicleFlags + + AircraftCache acache; + + /** We don't want GCC to zero our struct! It already is zeroed and has an index! */ + Aircraft() : SpecializedVehicleBase() {} + /** We want to 'destruct' the right class. */ + virtual ~Aircraft() { this->PreDestructor(); } + + void MarkDirty(); + void UpdateDeltaXY(Direction direction); + ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_AIRCRAFT_INC : EXPENSES_AIRCRAFT_RUN; } + bool IsPrimaryVehicle() const { return this->IsNormalAircraft(); } + SpriteID GetImage(Direction direction, EngineImageType image_type) const; + int GetDisplaySpeed() const { return this->cur_speed; } + int GetDisplayMaxSpeed() const { return this->vcache.cached_max_speed; } + int GetSpeedOldUnits() const { return this->vcache.cached_max_speed * 10 / 128; } + int GetCurrentMaxSpeed() const { return this->GetSpeedOldUnits(); } + Money GetRunningCost() const; + + bool IsInDepot() const + { + assert(this->IsPrimaryVehicle()); + return (this->vehstatus & VS_HIDDEN) != 0 && IsHangarTile(this->tile); + } + + bool Tick(); + void OnNewDay(); + uint Crash(bool flooded = false); + TileIndex GetOrderStationLocation(StationID station); + bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse); + + /** + * Check if the aircraft type is a normal flying device; eg + * not a rotor or a shadow + * @return Returns true if the aircraft is a helicopter/airplane and + * false if it is a shadow or a rotor + */ + inline bool IsNormalAircraft() const + { + /* To be fully correct the commented out functionality is the proper one, + * but since value can only be 0 or 2, it is sufficient to only check <= 2 + * return (this->subtype == AIR_HELICOPTER) || (this->subtype == AIR_AIRCRAFT); */ + return this->subtype <= AIR_AIRCRAFT; + } + + /** + * Get the range of this aircraft. + * @return Range in tiles or 0 if unlimited range. + */ + uint16 GetRange() const + { + return this->acache.cached_max_range; + } +}; + +/** + * Macro for iterating over all aircrafts. + */ +#define FOR_ALL_AIRCRAFT(var) FOR_ALL_VEHICLES_OF_TYPE(Aircraft, var) + +SpriteID GetRotorImage(const Aircraft *v, EngineImageType image_type); + +Station *GetTargetAirportIfValid(const Aircraft *v); + +#endif /* AIRCRAFT_H */ diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp new file mode 100644 index 0000000..a882d6e --- /dev/null +++ b/src/aircraft_cmd.cpp @@ -0,0 +1,2078 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** + * @file aircraft_cmd.cpp + * This file deals with aircraft and airport movements functionalities + */ + +#include "stdafx.h" +#include "aircraft.h" +#include "landscape.h" +#include "news_func.h" +#include "newgrf_engine.h" +#include "newgrf_sound.h" +#include "spritecache.h" +#include "strings_func.h" +#include "command_func.h" +#include "window_func.h" +#include "date_func.h" +#include "vehicle_func.h" +#include "sound_func.h" +#include "cheat_type.h" +#include "company_base.h" +#include "ai/ai.hpp" +#include "game/game.hpp" +#include "company_func.h" +#include "effectvehicle_func.h" +#include "station_base.h" +#include "engine_base.h" +#include "core/random_func.hpp" +#include "core/backup_type.hpp" +#include "infrastructure_func.h" +#include "zoom_func.h" +#include "disaster_vehicle.h" + +#include "table/strings.h" + +#include "safeguards.h" + +void Aircraft::UpdateDeltaXY(Direction direction) +{ + this->x_offs = -1; + this->y_offs = -1; + this->x_extent = 2; + this->y_extent = 2; + + switch (this->subtype) { + default: NOT_REACHED(); + + case AIR_AIRCRAFT: + case AIR_HELICOPTER: + switch (this->state) { + default: break; + case ENDTAKEOFF: + case LANDING: + case HELILANDING: + case FLYING: + this->x_extent = 24; + this->y_extent = 24; + break; + } + this->z_extent = 5; + break; + + case AIR_SHADOW: + this->z_extent = 1; + this->x_offs = 0; + this->y_offs = 0; + break; + + case AIR_ROTOR: + this->z_extent = 1; + break; + } +} + +static bool AirportMove(Aircraft *v, const AirportFTAClass *apc); +static bool AirportSetBlocks(Aircraft *v, const AirportFTA *current_pos, const AirportFTAClass *apc); +static bool AirportHasBlock(Aircraft *v, const AirportFTA *current_pos, const AirportFTAClass *apc); +static bool AirportFindFreeTerminal(Aircraft *v, const AirportFTAClass *apc); +static bool AirportFindFreeHelipad(Aircraft *v, const AirportFTAClass *apc); +static void CrashAirplane(Aircraft *v); + +static const SpriteID _aircraft_sprite[] = { + 0x0EB5, 0x0EBD, 0x0EC5, 0x0ECD, + 0x0ED5, 0x0EDD, 0x0E9D, 0x0EA5, + 0x0EAD, 0x0EE5, 0x0F05, 0x0F0D, + 0x0F15, 0x0F1D, 0x0F25, 0x0F2D, + 0x0EED, 0x0EF5, 0x0EFD, 0x0F35, + 0x0E9D, 0x0EA5, 0x0EAD, 0x0EB5, + 0x0EBD, 0x0EC5 +}; + +template <> +bool IsValidImageIndex(uint8 image_index) +{ + return image_index < lengthof(_aircraft_sprite); +} + +/** Helicopter rotor animation states */ +enum HelicopterRotorStates { + HRS_ROTOR_STOPPED, + HRS_ROTOR_MOVING_1, + HRS_ROTOR_MOVING_2, + HRS_ROTOR_MOVING_3, +}; + +/** + * Find the nearest hangar to v + * INVALID_STATION is returned, if the company does not have any suitable + * airports (like helipads only) + * @param v vehicle looking for a hangar + * @return the StationID if one is found, otherwise, INVALID_STATION + */ +static StationID FindNearestHangar(const Aircraft *v) +{ + const Station *st; + uint best = 0; + StationID index = INVALID_STATION; + TileIndex vtile = TileVirtXY(v->x_pos, v->y_pos); + const AircraftVehicleInfo *avi = AircraftVehInfo(v->engine_type); + + FOR_ALL_STATIONS(st) { + if (!IsInfraUsageAllowed(VEH_AIRCRAFT, v->owner, st->owner) || !(st->facilities & FACIL_AIRPORT)) continue; + + const AirportFTAClass *afc = st->airport.GetFTA(); + if (!st->airport.HasHangar() || ( + /* don't crash the plane if we know it can't land at the airport */ + (afc->flags & AirportFTAClass::SHORT_STRIP) && + (avi->subtype & AIR_FAST) && + !_cheats.no_jetcrash.value)) { + continue; + } + + /* v->tile can't be used here, when aircraft is flying v->tile is set to 0 */ + uint distance = DistanceSquare(vtile, st->airport.tile); + if (v->acache.cached_max_range_sqr != 0) { + /* Check if our current destination can be reached from the depot airport. */ + const Station *cur_dest = GetTargetAirportIfValid(v); + if (cur_dest != NULL && DistanceSquare(st->airport.tile, cur_dest->airport.tile) > v->acache.cached_max_range_sqr) continue; + } + if (distance < best || index == INVALID_STATION) { + best = distance; + index = st->index; + } + } + return index; +} + +SpriteID Aircraft::GetImage(Direction direction, EngineImageType image_type) const +{ + uint8 spritenum = this->spritenum; + + if (is_custom_sprite(spritenum)) { + SpriteID sprite = GetCustomVehicleSprite(this, direction, image_type); + if (sprite != 0) return sprite; + + spritenum = this->GetEngine()->original_image_index; + } + + assert(IsValidImageIndex(spritenum)); + return direction + _aircraft_sprite[spritenum]; +} + +SpriteID GetRotorImage(const Aircraft *v, EngineImageType image_type) +{ + assert(v->subtype == AIR_HELICOPTER); + + const Aircraft *w = v->Next()->Next(); + if (is_custom_sprite(v->spritenum)) { + SpriteID sprite = GetCustomRotorSprite(v, false, image_type); + if (sprite != 0) return sprite; + } + + /* Return standard rotor sprites if there are no custom sprites for this helicopter */ + return SPR_ROTOR_STOPPED + w->state; +} + +static SpriteID GetAircraftIcon(EngineID engine, EngineImageType image_type) +{ + const Engine *e = Engine::Get(engine); + uint8 spritenum = e->u.air.image_index; + + if (is_custom_sprite(spritenum)) { + SpriteID sprite = GetCustomVehicleIcon(engine, DIR_W, image_type); + if (sprite != 0) return sprite; + + spritenum = e->original_image_index; + } + + assert(IsValidImageIndex(spritenum)); + return DIR_W + _aircraft_sprite[spritenum]; +} + +void DrawAircraftEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type) +{ + SpriteID sprite = GetAircraftIcon(engine, image_type); + const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL); + preferred_x = Clamp(preferred_x, + left - UnScaleGUI(real_sprite->x_offs), + right - UnScaleGUI(real_sprite->width) - UnScaleGUI(real_sprite->x_offs)); + DrawSprite(sprite, pal, preferred_x, y); + + if (!(AircraftVehInfo(engine)->subtype & AIR_CTOL)) { + SpriteID rotor_sprite = GetCustomRotorIcon(engine, image_type); + if (rotor_sprite == 0) rotor_sprite = SPR_ROTOR_STOPPED; + DrawSprite(rotor_sprite, PAL_NONE, preferred_x, y - ScaleGUITrad(5)); + } +} + +/** + * Get the size of the sprite of an aircraft sprite heading west (used for lists). + * @param engine The engine to get the sprite from. + * @param[out] width The width of the sprite. + * @param[out] height The height of the sprite. + * @param[out] xoffs Number of pixels to shift the sprite to the right. + * @param[out] yoffs Number of pixels to shift the sprite downwards. + * @param image_type Context the sprite is used in. + */ +void GetAircraftSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type) +{ + const Sprite *spr = GetSprite(GetAircraftIcon(engine, image_type), ST_NORMAL); + + width = UnScaleGUI(spr->width); + height = UnScaleGUI(spr->height); + xoffs = UnScaleGUI(spr->x_offs); + yoffs = UnScaleGUI(spr->y_offs); +} + +/** + * Build an aircraft. + * @param tile tile of the depot where aircraft is built. + * @param flags type of operation. + * @param e the engine to build. + * @param data unused. + * @param ret[out] the vehicle that has been built. + * @return the cost of this operation or an error. + */ +CommandCost CmdBuildAircraft(TileIndex tile, DoCommandFlag flags, const Engine *e, uint16 data, Vehicle **ret) +{ + const AircraftVehicleInfo *avi = &e->u.air; + const Station *st = Station::GetByTile(tile); + + /* Prevent building aircraft types at places which can't handle them */ + if (!CanVehicleUseStation(e->index, st)) return CMD_ERROR; + + /* Make sure all aircraft end up in the first tile of the hangar. */ + tile = st->airport.GetHangarTile(st->airport.GetHangarNum(tile)); + + if (flags & DC_EXEC) { + Aircraft *v = new Aircraft(); // aircraft + Aircraft *u = new Aircraft(); // shadow + *ret = v; + + v->direction = DIR_SE; + + v->owner = u->owner = _current_company; + + v->tile = tile; + + uint x = TileX(tile) * TILE_SIZE + 5; + uint y = TileY(tile) * TILE_SIZE + 3; + + v->x_pos = u->x_pos = x; + v->y_pos = u->y_pos = y; + + u->z_pos = GetSlopePixelZ(x, y); + v->z_pos = u->z_pos + 1; + + v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL; + u->vehstatus = VS_HIDDEN | VS_UNCLICKABLE | VS_SHADOW; + + v->spritenum = avi->image_index; + + v->cargo_cap = avi->passenger_capacity; + v->refit_cap = 0; + u->cargo_cap = avi->mail_capacity; + u->refit_cap = 0; + + v->cargo_type = e->GetDefaultCargoType(); + u->cargo_type = CT_MAIL; + + v->name = NULL; + v->last_station_visited = INVALID_STATION; + v->last_loading_station = INVALID_STATION; + + v->acceleration = avi->acceleration; + v->engine_type = e->index; + u->engine_type = e->index; + + v->subtype = (avi->subtype & AIR_CTOL ? AIR_AIRCRAFT : AIR_HELICOPTER); + v->UpdateDeltaXY(INVALID_DIR); + + u->subtype = AIR_SHADOW; + u->UpdateDeltaXY(INVALID_DIR); + + v->reliability = e->reliability; + v->reliability_spd_dec = e->reliability_spd_dec; + v->max_age = e->GetLifeLengthInDays(); + + _new_vehicle_id = v->index; + + v->pos = GetVehiclePosOnBuild(tile); + + v->state = HANGAR; + v->previous_pos = v->pos; + v->targetairport = GetStationIndex(tile); + v->SetNext(u); + + v->SetServiceInterval(Company::Get(_current_company)->settings.vehicle.servint_aircraft); + + v->date_of_last_service = _date; + v->build_year = u->build_year = _cur_year; + + v->cur_image = u->cur_image = SPR_IMG_QUERY; + + v->random_bits = VehicleRandomBits(); + u->random_bits = VehicleRandomBits(); + + v->vehicle_flags = 0; + if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE); + v->SetServiceIntervalIsPercent(Company::Get(_current_company)->settings.vehicle.servint_ispercent); + + v->InvalidateNewGRFCacheOfChain(); + + v->cargo_cap = e->DetermineCapacity(v, &u->cargo_cap); + + v->InvalidateNewGRFCacheOfChain(); + + UpdateAircraftCache(v, true); + + v->UpdatePosition(); + u->UpdatePosition(); + + /* Aircraft with 3 vehicles (chopper)? */ + if (v->subtype == AIR_HELICOPTER) { + Aircraft *w = new Aircraft(); + w->engine_type = e->index; + w->direction = DIR_N; + w->owner = _current_company; + w->x_pos = v->x_pos; + w->y_pos = v->y_pos; + w->z_pos = v->z_pos + ROTOR_Z_OFFSET; + w->vehstatus = VS_HIDDEN | VS_UNCLICKABLE; + w->spritenum = 0xFF; + w->subtype = AIR_ROTOR; + w->cur_image = SPR_ROTOR_STOPPED; + w->random_bits = VehicleRandomBits(); + /* Use rotor's air.state to store the rotor animation frame */ + w->state = HRS_ROTOR_STOPPED; + w->UpdateDeltaXY(INVALID_DIR); + + u->SetNext(w); + w->UpdatePosition(); + } + } + + return CommandCost(); +} + + +bool Aircraft::FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse) +{ + const Station *st = GetTargetAirportIfValid(this); + /* If the station is not a valid airport or if it has no hangars */ + if (st == NULL || !st->airport.HasHangar()) { + /* the aircraft has to search for a hangar on its own */ + StationID station = FindNearestHangar(this); + + if (station == INVALID_STATION) return false; + + st = Station::Get(station); + } + + if (location != NULL) *location = st->xy; + if (destination != NULL) *destination = st->index; + + return true; +} + +static void CheckIfAircraftNeedsService(Aircraft *v) +{ + if (Company::Get(v->owner)->settings.vehicle.servint_aircraft == 0 || !v->NeedsAutomaticServicing()) return; + if (v->IsChainInDepot()) { + VehicleServiceInDepot(v); + return; + } + + /* When we're parsing conditional orders and the like + * we don't want to consider going to a depot too. */ + if (!v->current_order.IsType(OT_GOTO_DEPOT) && !v->current_order.IsType(OT_GOTO_STATION)) return; + + const Station *st = Station::Get(v->current_order.GetDestination()); + + assert(st != NULL); + + /* only goto depot if the target airport has a depot */ + if (st->airport.HasHangar() && CanVehicleUseStation(v, st)) { + v->current_order.MakeGoToDepot(st->index, ODTFB_SERVICE); + SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); + } else if (v->current_order.IsType(OT_GOTO_DEPOT)) { + v->current_order.MakeDummy(); + SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); + } +} + +Money Aircraft::GetRunningCost() const +{ + const Engine *e = this->GetEngine(); + uint cost_factor = GetVehicleProperty(this, PROP_AIRCRAFT_RUNNING_COST_FACTOR, e->u.air.running_cost); + return GetPrice(PR_RUNNING_AIRCRAFT, cost_factor, e->GetGRF()); +} + +void Aircraft::OnNewDay() +{ + if (!this->IsNormalAircraft()) return; + + if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this); + + CheckOrders(this); + + CheckVehicleBreakdown(this); + AgeVehicle(this); + CheckIfAircraftNeedsService(this); + + if (this->running_ticks == 0) return; + + CommandCost cost(EXPENSES_AIRCRAFT_RUN, this->GetRunningCost() * this->running_ticks / (DAYS_IN_YEAR * DAY_TICKS)); + + this->profit_this_year -= cost.GetCost(); + this->running_ticks = 0; + + SubtractMoneyFromCompanyFract(this->owner, cost); + + SetWindowDirty(WC_VEHICLE_DETAILS, this->index); + SetWindowClassesDirty(WC_AIRCRAFT_LIST); +} + +static void HelicopterTickHandler(Aircraft *v) +{ + Aircraft *u = v->Next()->Next(); + + if (u->vehstatus & VS_HIDDEN) return; + + /* if true, helicopter rotors do not rotate. This should only be the case if a helicopter is + * loading/unloading at a terminal or stopped */ + if (v->current_order.IsType(OT_LOADING) || (v->vehstatus & VS_STOPPED)) { + if (u->cur_speed != 0) { + u->cur_speed++; + if (u->cur_speed >= 0x80 && u->state == HRS_ROTOR_MOVING_3) { + u->cur_speed = 0; + } + } + } else { + if (u->cur_speed == 0) { + u->cur_speed = 0x70; + } + if (u->cur_speed >= 0x50) { + u->cur_speed--; + } + } + + int tick = ++u->tick_counter; + int spd = u->cur_speed >> 4; + + SpriteID img; + if (spd == 0) { + u->state = HRS_ROTOR_STOPPED; + img = GetRotorImage(v, EIT_ON_MAP); + if (u->cur_image == img) return; + } else if (tick >= spd) { + u->tick_counter = 0; + u->state++; + if (u->state > HRS_ROTOR_MOVING_3) u->state = HRS_ROTOR_MOVING_1; + img = GetRotorImage(v, EIT_ON_MAP); + } else { + return; + } + + u->cur_image = img; + + u->UpdatePositionAndViewport(); +} + +/** + * Set aircraft position. + * @param v Aircraft to position. + * @param x New X position. + * @param y New y position. + * @param z New z position. + */ +void SetAircraftPosition(Aircraft *v, int x, int y, int z) +{ + v->x_pos = x; + v->y_pos = y; + v->z_pos = z; + + v->UpdatePosition(); + v->UpdateViewport(true, false); + if (v->subtype == AIR_HELICOPTER) v->Next()->Next()->cur_image = GetRotorImage(v, EIT_ON_MAP); + + Aircraft *u = v->Next(); + + int safe_x = Clamp(x, 0, MapMaxX() * TILE_SIZE); + int safe_y = Clamp(y - 1, 0, MapMaxY() * TILE_SIZE); + u->x_pos = x; + u->y_pos = y - ((v->z_pos - GetSlopePixelZ(safe_x, safe_y)) >> 3); + + safe_y = Clamp(u->y_pos, 0, MapMaxY() * TILE_SIZE); + u->z_pos = GetSlopePixelZ(safe_x, safe_y); + u->cur_image = v->cur_image; + + u->UpdatePositionAndViewport(); + + u = u->Next(); + if (u != NULL) { + u->x_pos = x; + u->y_pos = y; + u->z_pos = z + ROTOR_Z_OFFSET; + + u->UpdatePositionAndViewport(); + } +} + +/** + * Handle Aircraft specific tasks when an Aircraft enters a hangar + * @param *v Vehicle that enters the hangar + */ +void HandleAircraftEnterHangar(Aircraft *v) +{ + v->subspeed = 0; + v->progress = 0; + + Aircraft *u = v->Next(); + u->vehstatus |= VS_HIDDEN; + u = u->Next(); + if (u != NULL) { + u->vehstatus |= VS_HIDDEN; + u->cur_speed = 0; + } + + SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos); +} + +static void PlayAircraftSound(const Vehicle *v) +{ + if (!PlayVehicleSound(v, VSE_START)) { + SndPlayVehicleFx(AircraftVehInfo(v->engine_type)->sfx, v); + } +} + + +/** + * Update cached values of an aircraft. + * Currently caches callback 36 max speed. + * @param v Vehicle + * @param update_range Update the aircraft range. + */ +void UpdateAircraftCache(Aircraft *v, bool update_range) +{ + uint max_speed = GetVehicleProperty(v, PROP_AIRCRAFT_SPEED, 0); + if (max_speed != 0) { + /* Convert from original units to km-ish/h */ + max_speed = (max_speed * 128) / 10; + + v->vcache.cached_max_speed = max_speed; + } else { + /* Use the default max speed of the vehicle. */ + v->vcache.cached_max_speed = AircraftVehInfo(v->engine_type)->max_speed; + } + + /* Update cargo aging period. */ + v->vcache.cached_cargo_age_period = GetVehicleProperty(v, PROP_AIRCRAFT_CARGO_AGE_PERIOD, EngInfo(v->engine_type)->cargo_age_period); + Aircraft *u = v->Next(); // Shadow for mail + u->vcache.cached_cargo_age_period = GetVehicleProperty(u, PROP_AIRCRAFT_CARGO_AGE_PERIOD, EngInfo(u->engine_type)->cargo_age_period); + + /* Update aircraft range. */ + if (update_range) { + v->acache.cached_max_range = GetVehicleProperty(v, PROP_AIRCRAFT_RANGE, AircraftVehInfo(v->engine_type)->max_range); + /* Squared it now so we don't have to do it later all the time. */ + v->acache.cached_max_range_sqr = v->acache.cached_max_range * v->acache.cached_max_range; + } +} + + +/** + * Special velocities for aircraft + */ +enum AircraftSpeedLimits { + SPEED_LIMIT_TAXI = 50, ///< Maximum speed of an aircraft while taxiing + SPEED_LIMIT_APPROACH = 230, ///< Maximum speed of an aircraft on finals + SPEED_LIMIT_BROKEN = 320, ///< Maximum speed of an aircraft that is broken + SPEED_LIMIT_HOLD = 425, ///< Maximum speed of an aircraft that flies the holding pattern + SPEED_LIMIT_NONE = 0xFFFF, ///< No environmental speed limit. Speed limit is type dependent +}; + +/** + * Sets the new speed for an aircraft + * @param v The vehicle for which the speed should be obtained + * @param speed_limit The maximum speed the vehicle may have. + * @param hard_limit If true, the limit is directly enforced, otherwise the plane is slowed down gradually + * @return The number of position updates needed within the tick + */ +static int UpdateAircraftSpeed(Aircraft *v, uint speed_limit = SPEED_LIMIT_NONE, bool hard_limit = true) +{ + /** + * 'acceleration' has the unit 3/8 mph/tick. This function is called twice per tick. + * So the speed amount we need to accelerate is: + * acceleration * 3 / 16 mph = acceleration * 3 / 16 * 16 / 10 km-ish/h + * = acceleration * 3 / 10 * 256 * (km-ish/h / 256) + * ~ acceleration * 77 (km-ish/h / 256) + */ + uint spd = v->acceleration * 77; + byte t; + + /* Adjust speed limits by plane speed factor to prevent taxiing + * and take-off speeds being too low. */ + speed_limit *= _settings_game.vehicle.plane_speed; + + if (v->vcache.cached_max_speed < speed_limit) { + if (v->cur_speed < speed_limit) hard_limit = false; + speed_limit = v->vcache.cached_max_speed; + } + + v->subspeed = (t = v->subspeed) + (byte)spd; + + /* Aircraft's current speed is used twice so that very fast planes are + * forced to slow down rapidly in the short distance needed. The magic + * value 16384 was determined to give similar results to the old speed/48 + * method at slower speeds. This also results in less reduction at slow + * speeds to that aircraft do not get to taxi speed straight after + * touchdown. */ + if (!hard_limit && v->cur_speed > speed_limit) { + speed_limit = v->cur_speed - max(1, ((v->cur_speed * v->cur_speed) / 16384) / _settings_game.vehicle.plane_speed); + } + + spd = min(v->cur_speed + (spd >> 8) + (v->subspeed < t), speed_limit); + + /* adjust speed for broken vehicles */ + if (v->vehstatus & VS_AIRCRAFT_BROKEN) spd = min(spd, SPEED_LIMIT_BROKEN); + + /* updates statusbar only if speed have changed to save CPU time */ + if (spd != v->cur_speed) { + v->cur_speed = spd; + SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); + } + + /* Adjust distance moved by plane speed setting */ + if (_settings_game.vehicle.plane_speed > 1) spd /= _settings_game.vehicle.plane_speed; + + /* Convert direction-independent speed into direction-dependent speed. (old movement method) */ + spd = v->GetOldAdvanceSpeed(spd); + + spd += v->progress; + v->progress = (byte)spd; + return spd >> 8; +} + +/** + * Get the tile height below the aircraft. + * This function is needed because aircraft can leave the mapborders. + * + * @param v The vehicle to get the height for. + * @return The height in pixels from 'z_pos' 0. + */ +int GetTileHeightBelowAircraft(const Vehicle *v) +{ + int safe_x = Clamp(v->x_pos, 0, MapMaxX() * TILE_SIZE); + int safe_y = Clamp(v->y_pos, 0, MapMaxY() * TILE_SIZE); + return TileHeight(TileVirtXY(safe_x, safe_y)) * TILE_HEIGHT; +} + +/** + * Get the 'flight level' bounds, in pixels from 'z_pos' 0 for a particular + * vehicle for normal flight situation. + * When the maximum is reached the vehicle should consider descending. + * When the minimum is reached the vehicle should consider ascending. + * + * @param v The vehicle to get the flight levels for. + * @param [out] min_level The minimum bounds for flight level. + * @param [out] max_level The maximum bounds for flight level. + */ +void GetAircraftFlightLevelBounds(const Vehicle *v, int *min_level, int *max_level) +{ + int base_altitude = GetTileHeightBelowAircraft(v); + if (v->type == VEH_AIRCRAFT && Aircraft::From(v)->subtype == AIR_HELICOPTER) { + base_altitude += HELICOPTER_HOLD_MAX_FLYING_ALTITUDE - PLANE_HOLD_MAX_FLYING_ALTITUDE; + } + + /* Make sure eastbound and westbound planes do not "crash" into each + * other by providing them with vertical separation + */ + switch (v->direction) { + case DIR_N: + case DIR_NE: + case DIR_E: + case DIR_SE: + base_altitude += 10; + break; + + default: break; + } + + /* Make faster planes fly higher so that they can overtake slower ones */ + base_altitude += min(20 * (v->vcache.cached_max_speed / 200) - 90, 0); + + if (min_level != NULL) *min_level = base_altitude + AIRCRAFT_MIN_FLYING_ALTITUDE; + if (max_level != NULL) *max_level = base_altitude + AIRCRAFT_MAX_FLYING_ALTITUDE; +} + +/** + * Gets the maximum 'flight level' for the holding pattern of the aircraft, + * in pixels 'z_pos' 0, depending on terrain below.. + * + * @param v The aircraft that may or may not need to decrease its altitude. + * @return Maximal aircraft holding altitude, while in normal flight, in pixels. + */ +int GetAircraftHoldMaxAltitude(const Aircraft *v) +{ + int tile_height = GetTileHeightBelowAircraft(v); + + return tile_height + ((v->subtype == AIR_HELICOPTER) ? HELICOPTER_HOLD_MAX_FLYING_ALTITUDE : PLANE_HOLD_MAX_FLYING_ALTITUDE); +} + +template +int GetAircraftFlightLevel(T *v, bool takeoff) +{ + /* Aircraft is in flight. We want to enforce it being somewhere + * between the minimum and the maximum allowed altitude. */ + int aircraft_min_altitude; + int aircraft_max_altitude; + GetAircraftFlightLevelBounds(v, &aircraft_min_altitude, &aircraft_max_altitude); + int aircraft_middle_altitude = (aircraft_min_altitude + aircraft_max_altitude) / 2; + + /* If those assumptions would be violated, aircrafts would behave fairly strange. */ + assert(aircraft_min_altitude < aircraft_middle_altitude); + assert(aircraft_middle_altitude < aircraft_max_altitude); + + int z = v->z_pos; + if (z < aircraft_min_altitude || + (HasBit(v->flags, VAF_IN_MIN_HEIGHT_CORRECTION) && z < aircraft_middle_altitude)) { + /* Ascend. And don't fly into that mountain right ahead. + * And avoid our aircraft become a stairclimber, so if we start + * correcting altitude, then we stop correction not too early. */ + SetBit(v->flags, VAF_IN_MIN_HEIGHT_CORRECTION); + z += takeoff ? 2 : 1; + } else if (!takeoff && (z > aircraft_max_altitude || + (HasBit(v->flags, VAF_IN_MAX_HEIGHT_CORRECTION) && z > aircraft_middle_altitude))) { + /* Descend lower. You are an aircraft, not an space ship. + * And again, don't stop correcting altitude too early. */ + SetBit(v->flags, VAF_IN_MAX_HEIGHT_CORRECTION); + z--; + } else if (HasBit(v->flags, VAF_IN_MIN_HEIGHT_CORRECTION) && z >= aircraft_middle_altitude) { + /* Now, we have corrected altitude enough. */ + ClrBit(v->flags, VAF_IN_MIN_HEIGHT_CORRECTION); + } else if (HasBit(v->flags, VAF_IN_MAX_HEIGHT_CORRECTION) && z <= aircraft_middle_altitude) { + /* Now, we have corrected altitude enough. */ + ClrBit(v->flags, VAF_IN_MAX_HEIGHT_CORRECTION); + } + + return z; +} + +template int GetAircraftFlightLevel(DisasterVehicle *v, bool takeoff); + +/** + * Find the entry point to an airport depending on direction which + * the airport is being approached from. Each airport can have up to + * four entry points for its approach system so that approaching + * aircraft do not fly through each other or are forced to do 180 + * degree turns during the approach. The arrivals are grouped into + * four sectors dependent on the DiagDirection from which the airport + * is approached. + * + * @param v The vehicle that is approaching the airport + * @param apc The Airport Class being approached. + * @param rotation The rotation of the airport. + * @return The index of the entry point + */ +static byte AircraftGetEntryPoint(const Aircraft *v, const AirportFTAClass *apc, Direction rotation) +{ + assert(v != NULL); + assert(apc != NULL); + + /* In the case the station doesn't exit anymore, set target tile 0. + * It doesn't hurt much, aircraft will go to next order, nearest hangar + * or it will simply crash in next tick */ + TileIndex tile = 0; + + const Station *st = Station::GetIfValid(v->targetairport); + if (st != NULL) { + /* Make sure we don't go to INVALID_TILE if the airport has been removed. */ + tile = (st->airport.tile != INVALID_TILE) ? st->airport.tile : st->xy; + } + + int delta_x = v->x_pos - TileX(tile) * TILE_SIZE; + int delta_y = v->y_pos - TileY(tile) * TILE_SIZE; + + DiagDirection dir; + if (abs(delta_y) < abs(delta_x)) { + /* We are northeast or southwest of the airport */ + dir = delta_x < 0 ? DIAGDIR_NE : DIAGDIR_SW; + } else { + /* We are northwest or southeast of the airport */ + dir = delta_y < 0 ? DIAGDIR_NW : DIAGDIR_SE; + } + dir = ChangeDiagDir(dir, DiagDirDifference(DIAGDIR_NE, DirToDiagDir(rotation))); + return apc->entry_points[dir]; +} + + +static void MaybeCrashAirplane(Aircraft *v); + +/** + * Controls the movement of an aircraft. This function actually moves the vehicle + * on the map and takes care of minor things like sound playback. + * @todo De-mystify the cur_speed values for helicopter rotors. + * @param v The vehicle that is moved. Must be the first vehicle of the chain + * @return Whether the position requested by the State Machine has been reached + */ +static bool AircraftController(Aircraft *v) +{ + int count; + + /* NULL if station is invalid */ + const Station *st = Station::GetIfValid(v->targetairport); + /* INVALID_TILE if there is no station */ + TileIndex tile = INVALID_TILE; + Direction rotation = DIR_N; + uint size_x = 1, size_y = 1; + if (st != NULL) { + if (st->airport.tile != INVALID_TILE) { + tile = st->airport.tile; + rotation = st->airport.rotation; + size_x = st->airport.w; + size_y = st->airport.h; + } else { + tile = st->xy; + } + } + /* DUMMY if there is no station or no airport */ + const AirportFTAClass *afc = tile == INVALID_TILE ? GetAirport(AT_DUMMY) : st->airport.GetFTA(); + + /* prevent going to INVALID_TILE if airport is deleted. */ + if (st == NULL || st->airport.tile == INVALID_TILE) { + /* Jump into our "holding pattern" state machine if possible */ + if (v->pos >= afc->nofelements) { + v->pos = v->previous_pos = AircraftGetEntryPoint(v, afc, DIR_N); + } else if (v->targetairport != v->current_order.GetDestination()) { + /* If not possible, just get out of here fast */ + v->state = FLYING; + UpdateAircraftCache(v); + AircraftNextAirportPos_and_Order(v); + /* get aircraft back on running altitude */ + SetAircraftPosition(v, v->x_pos, v->y_pos, GetAircraftFlightLevel(v)); + return false; + } + } + + /* get airport moving data */ + const AirportMovingData amd = RotateAirportMovingData(afc->MovingData(v->pos), rotation, size_x, size_y); + + int x = TileX(tile) * TILE_SIZE; + int y = TileY(tile) * TILE_SIZE; + + /* Helicopter raise */ + if (amd.flag & AMED_HELI_RAISE) { + Aircraft *u = v->Next()->Next(); + + /* Make sure the rotors don't rotate too fast */ + if (u->cur_speed > 32) { + v->cur_speed = 0; + if (--u->cur_speed == 32) { + if (!PlayVehicleSound(v, VSE_START)) { + SndPlayVehicleFx(SND_18_HELICOPTER, v); + } + } + } else { + u->cur_speed = 32; + count = UpdateAircraftSpeed(v); + if (count > 0) { + v->tile = 0; + + int z_dest; + GetAircraftFlightLevelBounds(v, &z_dest, NULL); + + /* Reached altitude? */ + if (v->z_pos >= z_dest) { + v->cur_speed = 0; + return true; + } + SetAircraftPosition(v, v->x_pos, v->y_pos, min(v->z_pos + count, z_dest)); + } + } + return false; + } + + /* Helicopter landing. */ + if (amd.flag & AMED_HELI_LOWER) { + if (st == NULL) { + /* FIXME - AircraftController -> if station no longer exists, do not land + * helicopter will circle until sign disappears, then go to next order + * what to do when it is the only order left, right now it just stays in 1 place */ + v->state = FLYING; + UpdateAircraftCache(v); + AircraftNextAirportPos_and_Order(v); + return false; + } + + /* Vehicle is now at the airport. */ + v->tile = tile; + + /* Find altitude of landing position. */ + int z = GetSlopePixelZ(x, y) + 1 + afc->delta_z; + + if (z == v->z_pos) { + Vehicle *u = v->Next()->Next(); + + /* Increase speed of rotors. When speed is 80, we've landed. */ + if (u->cur_speed >= 80) return true; + u->cur_speed += 4; + } else { + count = UpdateAircraftSpeed(v); + if (count > 0) { + if (v->z_pos > z) { + SetAircraftPosition(v, v->x_pos, v->y_pos, max(v->z_pos - count, z)); + } else { + SetAircraftPosition(v, v->x_pos, v->y_pos, min(v->z_pos + count, z)); + } + } + } + return false; + } + + /* Get distance from destination pos to current pos. */ + uint dist = abs(x + amd.x - v->x_pos) + abs(y + amd.y - v->y_pos); + + /* Need exact position? */ + if (!(amd.flag & AMED_EXACTPOS) && dist <= (amd.flag & AMED_SLOWTURN ? 8U : 4U)) return true; + + /* At final pos? */ + if (dist == 0) { + /* Change direction smoothly to final direction. */ + DirDiff dirdiff = DirDifference(amd.direction, v->direction); + /* if distance is 0, and plane points in right direction, no point in calling + * UpdateAircraftSpeed(). So do it only afterwards */ + if (dirdiff == DIRDIFF_SAME) { + v->cur_speed = 0; + return true; + } + + if (!UpdateAircraftSpeed(v, SPEED_LIMIT_TAXI)) return false; + + v->direction = ChangeDir(v->direction, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT); + v->cur_speed >>= 1; + + SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos); + return false; + } + + if (amd.flag & AMED_BRAKE && v->cur_speed > SPEED_LIMIT_TAXI * _settings_game.vehicle.plane_speed) { + MaybeCrashAirplane(v); + if ((v->vehstatus & VS_CRASHED) != 0) return false; + } + + uint speed_limit = SPEED_LIMIT_TAXI; + bool hard_limit = true; + + if (amd.flag & AMED_NOSPDCLAMP) speed_limit = SPEED_LIMIT_NONE; + if (amd.flag & AMED_HOLD) { speed_limit = SPEED_LIMIT_HOLD; hard_limit = false; } + if (amd.flag & AMED_LAND) { speed_limit = SPEED_LIMIT_APPROACH; hard_limit = false; } + if (amd.flag & AMED_BRAKE) { speed_limit = SPEED_LIMIT_TAXI; hard_limit = false; } + + count = UpdateAircraftSpeed(v, speed_limit, hard_limit); + if (count == 0) return false; + + if (v->turn_counter != 0) v->turn_counter--; + + do { + + GetNewVehiclePosResult gp; + + if (dist < 4 || (amd.flag & AMED_LAND)) { + /* move vehicle one pixel towards target */ + gp.x = (v->x_pos != (x + amd.x)) ? + v->x_pos + ((x + amd.x > v->x_pos) ? 1 : -1) : + v->x_pos; + gp.y = (v->y_pos != (y + amd.y)) ? + v->y_pos + ((y + amd.y > v->y_pos) ? 1 : -1) : + v->y_pos; + + /* Oilrigs must keep v->tile as st->airport.tile, since the landing pad is in a non-airport tile */ + gp.new_tile = (st->airport.type == AT_OILRIG) ? st->airport.tile : TileVirtXY(gp.x, gp.y); + + } else { + + /* Turn. Do it slowly if in the air. */ + Direction newdir = GetDirectionTowards(v, x + amd.x, y + amd.y); + if (newdir != v->direction) { + if (amd.flag & AMED_SLOWTURN && v->number_consecutive_turns < 8 && v->subtype == AIR_AIRCRAFT) { + if (v->turn_counter == 0 || newdir == v->last_direction) { + if (newdir == v->last_direction) { + v->number_consecutive_turns = 0; + } else { + v->number_consecutive_turns++; + } + v->turn_counter = 2 * _settings_game.vehicle.plane_speed; + v->last_direction = v->direction; + v->direction = newdir; + } + + /* Move vehicle. */ + gp = GetNewVehiclePos(v); + } else { + v->cur_speed >>= 1; + v->direction = newdir; + + /* When leaving a terminal an aircraft often goes to a position + * directly in front of it. If it would move while turning it + * would need an two extra turns to end up at the correct position. + * To make it easier just disallow all moving while turning as + * long as an aircraft is on the ground. */ + gp.x = v->x_pos; + gp.y = v->y_pos; + gp.new_tile = gp.old_tile = v->tile; + } + } else { + v->number_consecutive_turns = 0; + /* Move vehicle. */ + gp = GetNewVehiclePos(v); + } + } + + v->tile = gp.new_tile; + /* If vehicle is in the air, use tile coordinate 0. */ + if (amd.flag & (AMED_TAKEOFF | AMED_SLOWTURN | AMED_LAND)) v->tile = 0; + + /* Adjust Z for land or takeoff? */ + int z = v->z_pos; + + if (amd.flag & AMED_TAKEOFF) { + z = GetAircraftFlightLevel(v, true); + } else if (amd.flag & AMED_HOLD) { + /* Let the plane drop from normal flight altitude to holding pattern altitude */ + if (z > GetAircraftHoldMaxAltitude(v)) z--; + } else if ((amd.flag & AMED_SLOWTURN) && (amd.flag & AMED_NOSPDCLAMP)) { + z = GetAircraftFlightLevel(v); + } + + if (amd.flag & AMED_LAND) { + if (st->airport.tile == INVALID_TILE) { + /* Airport has been removed, abort the landing procedure */ + v->state = FLYING; + UpdateAircraftCache(v); + AircraftNextAirportPos_and_Order(v); + /* get aircraft back on running altitude */ + SetAircraftPosition(v, gp.x, gp.y, GetAircraftFlightLevel(v)); + continue; + } + + int curz = GetSlopePixelZ(x + amd.x, y + amd.y) + 1; + + /* We're not flying below our destination, right? */ + assert(curz <= z); + int t = max(1U, dist - 4); + int delta = z - curz; + + /* Only start lowering when we're sufficiently close for a 1:1 glide */ + if (delta >= t) { + z -= CeilDiv(z - curz, t); + } + if (z < curz) z = curz; + } + + /* We've landed. Decrease speed when we're reaching end of runway. */ + if (amd.flag & AMED_BRAKE) { + int curz = GetSlopePixelZ(x, y) + 1; + + if (z > curz) { + z--; + } else if (z < curz) { + z++; + } + + } + + SetAircraftPosition(v, gp.x, gp.y, z); + } while (--count != 0); + return false; +} + +/** + * Handle crashed aircraft \a v. + * @param v Crashed aircraft. + */ +static bool HandleCrashedAircraft(Aircraft *v) +{ + v->crashed_counter += 3; + + Station *st = GetTargetAirportIfValid(v); + + /* make aircraft crash down to the ground */ + if (v->crashed_counter < 500 && st == NULL && ((v->crashed_counter % 3) == 0) ) { + int z = GetSlopePixelZ(Clamp(v->x_pos, 0, MapMaxX() * TILE_SIZE), Clamp(v->y_pos, 0, MapMaxY() * TILE_SIZE)); + v->z_pos -= 1; + if (v->z_pos == z) { + v->crashed_counter = 500; + v->z_pos++; + } + } + + if (v->crashed_counter < 650) { + uint32 r; + if (Chance16R(1, 32, r)) { + static const DirDiff delta[] = { + DIRDIFF_45LEFT, DIRDIFF_SAME, DIRDIFF_SAME, DIRDIFF_45RIGHT + }; + + v->direction = ChangeDir(v->direction, delta[GB(r, 16, 2)]); + SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos); + r = Random(); + CreateEffectVehicleRel(v, + GB(r, 0, 4) - 4, + GB(r, 4, 4) - 4, + GB(r, 8, 4), + EV_EXPLOSION_SMALL); + } + } else if (v->crashed_counter >= 10000) { + /* remove rubble of crashed airplane */ + + /* clear runway-in on all airports, set by crashing plane + * small airports use AIRPORT_BUSY, city airports use RUNWAY_IN_OUT_block, etc. + * but they all share the same number */ + if (st != NULL) { + CLRBITS(st->airport.flags, RUNWAY_IN_block); + CLRBITS(st->airport.flags, RUNWAY_IN_OUT_block); // commuter airport + CLRBITS(st->airport.flags, RUNWAY_IN2_block); // intercontinental + } + + delete v; + + return false; + } + + return true; +} + + +/** + * Handle smoke of broken aircraft. + * @param v Aircraft + * @param mode Is this the non-first call for this vehicle in this tick? + */ +static void HandleAircraftSmoke(Aircraft *v, bool mode) +{ + static const struct { + int8 x; + int8 y; + } smoke_pos[] = { + { 5, 5 }, + { 6, 0 }, + { 5, -5 }, + { 0, -6 }, + { -5, -5 }, + { -6, 0 }, + { -5, 5 }, + { 0, 6 } + }; + + if (!(v->vehstatus & VS_AIRCRAFT_BROKEN)) return; + + /* Stop smoking when landed */ + if (v->cur_speed < 10) { + v->vehstatus &= ~VS_AIRCRAFT_BROKEN; + v->breakdown_ctr = 0; + return; + } + + /* Spawn effect et most once per Tick, i.e. !mode */ + if (!mode && (v->tick_counter & 0x0F) == 0) { + CreateEffectVehicleRel(v, + smoke_pos[v->direction].x, + smoke_pos[v->direction].y, + 2, + EV_BREAKDOWN_SMOKE_AIRCRAFT + ); + } +} + +void HandleMissingAircraftOrders(Aircraft *v) +{ + /* + * We do not have an order. This can be divided into two cases: + * 1) we are heading to an invalid station. In this case we must + * find another airport to go to. If there is nowhere to go, + * we will destroy the aircraft as it otherwise will enter + * the holding pattern for the first airport, which can cause + * the plane to go into an undefined state when building an + * airport with the same StationID. + * 2) we are (still) heading to a (still) valid airport, then we + * can continue going there. This can happen when you are + * changing the aircraft's orders while in-flight or in for + * example a depot. However, when we have a current order to + * go to a depot, we have to keep that order so the aircraft + * actually stops. + */ + const Station *st = GetTargetAirportIfValid(v); + if (st == NULL) { + Backup cur_company(_current_company, v->owner, FILE_LINE); + CommandCost ret = DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_SEND_VEHICLE_TO_DEPOT); + cur_company.Restore(); + + if (ret.Failed()) CrashAirplane(v); + } else if (!v->current_order.IsType(OT_GOTO_DEPOT)) { + v->current_order.Free(); + } +} + + +TileIndex Aircraft::GetOrderStationLocation(StationID station) +{ + /* Orders are changed in flight, ensure going to the right station. */ + if (this->state == FLYING) { + AircraftNextAirportPos_and_Order(this); + } + + /* Aircraft do not use dest-tile */ + return 0; +} + +void Aircraft::MarkDirty() +{ + this->colourmap = PAL_NONE; + this->UpdateViewport(true, false); + if (this->subtype == AIR_HELICOPTER) this->Next()->Next()->cur_image = GetRotorImage(this, EIT_ON_MAP); +} + + +uint Aircraft::Crash(bool flooded) +{ + uint pass = Vehicle::Crash(flooded) + 2; // pilots + this->crashed_counter = flooded ? 9000 : 0; // max 10000, disappear pretty fast when flooded + + return pass; +} + +/** + * Bring the aircraft in a crashed state, create the explosion animation, and create a news item about the crash. + * @param v Aircraft that crashed. + */ +static void CrashAirplane(Aircraft *v) +{ + CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE); + + uint pass = v->Crash(); + SetDParam(0, pass); + + v->cargo.Truncate(); + v->Next()->cargo.Truncate(); + const Station *st = GetTargetAirportIfValid(v); + StringID newsitem; + if (st == NULL) { + newsitem = STR_NEWS_PLANE_CRASH_OUT_OF_FUEL; + } else { + SetDParam(1, st->index); + newsitem = STR_NEWS_AIRCRAFT_CRASH; + } + + AI::NewEvent(v->owner, new ScriptEventVehicleCrashed(v->index, v->tile, st == NULL ? ScriptEventVehicleCrashed::CRASH_AIRCRAFT_NO_AIRPORT : ScriptEventVehicleCrashed::CRASH_PLANE_LANDING)); + Game::NewEvent(new ScriptEventVehicleCrashed(v->index, v->tile, st == NULL ? ScriptEventVehicleCrashed::CRASH_AIRCRAFT_NO_AIRPORT : ScriptEventVehicleCrashed::CRASH_PLANE_LANDING)); + + AddVehicleNewsItem(newsitem, NT_ACCIDENT, v->index, st != NULL ? st->index : INVALID_STATION); + + ModifyStationRatingAround(v->tile, v->owner, -160, 30); + if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, v); +} + +/** + * Decide whether aircraft \a v should crash. + * @param v Aircraft to test. + */ +static void MaybeCrashAirplane(Aircraft *v) +{ + if (_settings_game.vehicle.plane_crashes == 0) return; + + Station *st = Station::Get(v->targetairport); + + /* FIXME -- MaybeCrashAirplane -> increase crashing chances of very modern airplanes on smaller than AT_METROPOLITAN airports */ + uint32 prob = (0x4000 << _settings_game.vehicle.plane_crashes); + if ((st->airport.GetFTA()->flags & AirportFTAClass::SHORT_STRIP) && + (AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) && + !_cheats.no_jetcrash.value) { + prob /= 20; + } else { + prob /= 1500; + } + + if (GB(Random(), 0, 22) > prob) return; + + /* Crash the airplane. Remove all goods stored at the station. */ + for (CargoID i = 0; i < NUM_CARGO; i++) { + st->goods[i].rating = 1; + st->goods[i].cargo.Truncate(); + } + + CrashAirplane(v); +} + +/** + * Aircraft arrives at a terminal. If it is the first aircraft, throw a party. + * Start loading cargo. + * @param v Aircraft that arrived. + */ +static void AircraftEntersTerminal(Aircraft *v) +{ + if (v->current_order.IsType(OT_GOTO_DEPOT)) return; + + Station *st = Station::Get(v->targetairport); + v->last_station_visited = v->targetairport; + + /* Check if station was ever visited before */ + if (!(st->had_vehicle_of_type & HVOT_AIRCRAFT)) { + st->had_vehicle_of_type |= HVOT_AIRCRAFT; + SetDParam(0, st->index); + /* show newsitem of celebrating citizens */ + AddVehicleNewsItem( + STR_NEWS_FIRST_AIRCRAFT_ARRIVAL, + (v->owner == _local_company) ? NT_ARRIVAL_COMPANY : NT_ARRIVAL_OTHER, + v->index, + st->index + ); + AI::NewEvent(v->owner, new ScriptEventStationFirstVehicle(st->index, v->index)); + Game::NewEvent(new ScriptEventStationFirstVehicle(st->index, v->index)); + } + + v->BeginLoading(); +} + +/** + * Aircraft touched down at the landing strip. + * @param v Aircraft that landed. + */ +static void AircraftLandAirplane(Aircraft *v) +{ + v->UpdateDeltaXY(INVALID_DIR); + + if (!PlayVehicleSound(v, VSE_TOUCHDOWN)) { + SndPlayVehicleFx(SND_17_SKID_PLANE, v); + } +} + + +/** set the right pos when heading to other airports after takeoff */ +void AircraftNextAirportPos_and_Order(Aircraft *v) +{ + if (v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_DEPOT)) { + v->targetairport = v->current_order.GetDestination(); + } + + const Station *st = GetTargetAirportIfValid(v); + const AirportFTAClass *apc = st == NULL ? GetAirport(AT_DUMMY) : st->airport.GetFTA(); + Direction rotation = st == NULL ? DIR_N : st->airport.rotation; + v->pos = v->previous_pos = AircraftGetEntryPoint(v, apc, rotation); +} + +/** + * Aircraft is about to leave the hangar. + * @param v Aircraft leaving. + * @param exit_dir The direction the vehicle leaves the hangar. + * @note This function is called in AfterLoadGame for old savegames, so don't rely + * on any data to be valid, especially don't rely on the fact that the vehicle + * is actually on the ground inside a depot. + */ +void AircraftLeaveHangar(Aircraft *v, Direction exit_dir) +{ + v->cur_speed = 0; + v->subspeed = 0; + v->progress = 0; + v->direction = exit_dir; + v->vehstatus &= ~VS_HIDDEN; + { + Vehicle *u = v->Next(); + u->vehstatus &= ~VS_HIDDEN; + + /* Rotor blades */ + u = u->Next(); + if (u != NULL) { + u->vehstatus &= ~VS_HIDDEN; + u->cur_speed = 80; + } + } + + VehicleServiceInDepot(v); + SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos); + InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); + SetWindowClassesDirty(WC_AIRCRAFT_LIST); +} + +//////////////////////////////////////////////////////////////////////////////// +/////////////////// AIRCRAFT MOVEMENT SCHEME //////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +static void AircraftEventHandler_EnterTerminal(Aircraft *v, const AirportFTAClass *apc) +{ + AircraftEntersTerminal(v); + v->state = apc->layout[v->pos].heading; +} + +/** + * Aircraft arrived in an airport hangar. + * @param v Aircraft in the hangar. + * @param apc Airport description containing the hangar. + */ +static void AircraftEventHandler_EnterHangar(Aircraft *v, const AirportFTAClass *apc) +{ + VehicleEnterDepot(v); + v->state = apc->layout[v->pos].heading; +} + +/** + * Handle aircraft movement/decision making in an airport hangar. + * @param v Aircraft in the hangar. + * @param apc Airport description containing the hangar. + */ +static void AircraftEventHandler_InHangar(Aircraft *v, const AirportFTAClass *apc) +{ + /* if we just arrived, execute EnterHangar first */ + if (v->previous_pos != v->pos) { + AircraftEventHandler_EnterHangar(v, apc); + return; + } + + /* if we were sent to the depot, stay there */ + if (v->current_order.IsType(OT_GOTO_DEPOT) && (v->vehstatus & VS_STOPPED)) { + v->current_order.Free(); + return; + } + + if (!v->current_order.IsType(OT_GOTO_STATION) && + !v->current_order.IsType(OT_GOTO_DEPOT)) + return; + + /* We are leaving a hangar, but have to go to the exact same one; re-enter */ + if (v->current_order.IsType(OT_GOTO_DEPOT) && v->current_order.GetDestination() == v->targetairport) { + VehicleEnterDepot(v); + return; + } + + /* if the block of the next position is busy, stay put */ + if (AirportHasBlock(v, &apc->layout[v->pos], apc)) return; + + /* We are already at the target airport, we need to find a terminal */ + if (v->current_order.GetDestination() == v->targetairport) { + /* FindFreeTerminal: + * 1. Find a free terminal, 2. Occupy it, 3. Set the vehicle's state to that terminal */ + if (v->subtype == AIR_HELICOPTER) { + if (!AirportFindFreeHelipad(v, apc)) return; // helicopter + } else { + if (!AirportFindFreeTerminal(v, apc)) return; // airplane + } + } else { // Else prepare for launch. + /* airplane goto state takeoff, helicopter to helitakeoff */ + v->state = (v->subtype == AIR_HELICOPTER) ? HELITAKEOFF : TAKEOFF; + } + const Station *st = Station::GetByTile(v->tile); + AircraftLeaveHangar(v, st->airport.GetHangarExitDirection(v->tile)); + AirportMove(v, apc); +} + +/** At one of the Airport's Terminals */ +static void AircraftEventHandler_AtTerminal(Aircraft *v, const AirportFTAClass *apc) +{ + /* if we just arrived, execute EnterTerminal first */ + if (v->previous_pos != v->pos) { + AircraftEventHandler_EnterTerminal(v, apc); + /* on an airport with helipads, a helicopter will always land there + * and get serviced at the same time - setting */ + if (_settings_game.order.serviceathelipad) { + if (v->subtype == AIR_HELICOPTER && apc->num_helipads > 0) { + /* an excerpt of ServiceAircraft, without the invisibility stuff */ + v->date_of_last_service = _date; + v->breakdowns_since_last_service = 0; + v->reliability = v->GetEngine()->reliability; + SetWindowDirty(WC_VEHICLE_DETAILS, v->index); + } + } + return; + } + + if (v->current_order.IsType(OT_NOTHING)) return; + + /* if the block of the next position is busy, stay put */ + if (AirportHasBlock(v, &apc->layout[v->pos], apc)) return; + + /* airport-road is free. We either have to go to another airport, or to the hangar + * ---> start moving */ + + bool go_to_hangar = false; + switch (v->current_order.GetType()) { + case OT_GOTO_STATION: // ready to fly to another airport + break; + case OT_GOTO_DEPOT: // visit hangar for servicing, sale, etc. + go_to_hangar = v->current_order.GetDestination() == v->targetairport; + break; + case OT_CONDITIONAL: + /* In case of a conditional order we just have to wait a tick + * longer, so the conditional order can actually be processed; + * we should not clear the order as that makes us go nowhere. */ + return; + default: // orders have been deleted (no orders), goto depot and don't bother us + v->current_order.Free(); + go_to_hangar = Station::Get(v->targetairport)->airport.HasHangar(); + } + + if (go_to_hangar) { + v->state = HANGAR; + } else { + /* airplane goto state takeoff, helicopter to helitakeoff */ + v->state = (v->subtype == AIR_HELICOPTER) ? HELITAKEOFF : TAKEOFF; + } + AirportMove(v, apc); +} + +static void AircraftEventHandler_General(Aircraft *v, const AirportFTAClass *apc) +{ + error("OK, you shouldn't be here, check your Airport Scheme!"); +} + +static void AircraftEventHandler_TakeOff(Aircraft *v, const AirportFTAClass *apc) +{ + PlayAircraftSound(v); // play takeoffsound for airplanes + v->state = STARTTAKEOFF; +} + +static void AircraftEventHandler_StartTakeOff(Aircraft *v, const AirportFTAClass *apc) +{ + v->state = ENDTAKEOFF; + v->UpdateDeltaXY(INVALID_DIR); +} + +static void AircraftEventHandler_EndTakeOff(Aircraft *v, const AirportFTAClass *apc) +{ + v->state = FLYING; + /* get the next position to go to, differs per airport */ + AircraftNextAirportPos_and_Order(v); +} + +static void AircraftEventHandler_HeliTakeOff(Aircraft *v, const AirportFTAClass *apc) +{ + v->state = FLYING; + v->UpdateDeltaXY(INVALID_DIR); + + /* get the next position to go to, differs per airport */ + AircraftNextAirportPos_and_Order(v); + + /* Send the helicopter to a hangar if needed for replacement */ + if (v->NeedsAutomaticServicing()) { + Backup cur_company(_current_company, v->owner, FILE_LINE); + DoCommand(v->tile, v->index | DEPOT_SERVICE | DEPOT_LOCATE_HANGAR, 0, DC_EXEC, CMD_SEND_VEHICLE_TO_DEPOT); + cur_company.Restore(); + } +} + +static void AircraftEventHandler_Flying(Aircraft *v, const AirportFTAClass *apc) +{ + Station *st = Station::Get(v->targetairport); + + /* Runway busy, not allowed to use this airstation or closed, circle. */ + if (CanVehicleUseStation(v, st) && IsInfraUsageAllowed(VEH_AIRCRAFT, v->owner, st->owner) && (st->owner == OWNER_NONE || st->owner == v->owner) && !(st->airport.flags & AIRPORT_CLOSED_block)) { + /* {32,FLYING,NOTHING_block,37}, {32,LANDING,N,33}, {32,HELILANDING,N,41}, + * if it is an airplane, look for LANDING, for helicopter HELILANDING + * it is possible to choose from multiple landing runways, so loop until a free one is found */ + byte landingtype = (v->subtype == AIR_HELICOPTER) ? HELILANDING : LANDING; + const AirportFTA *current = apc->layout[v->pos].next; + while (current != NULL) { + if (current->heading == landingtype) { + /* save speed before, since if AirportHasBlock is false, it resets them to 0 + * we don't want that for plane in air + * hack for speed thingie */ + uint16 tcur_speed = v->cur_speed; + uint16 tsubspeed = v->subspeed; + if (!AirportHasBlock(v, current, apc)) { + v->state = landingtype; // LANDING / HELILANDING + /* it's a bit dirty, but I need to set position to next position, otherwise + * if there are multiple runways, plane won't know which one it took (because + * they all have heading LANDING). And also occupy that block! */ + v->pos = current->next_position; + SETBITS(st->airport.flags, apc->layout[v->pos].block); + return; + } + v->cur_speed = tcur_speed; + v->subspeed = tsubspeed; + } + current = current->next; + } + } + v->state = FLYING; + v->pos = apc->layout[v->pos].next_position; +} + +static void AircraftEventHandler_Landing(Aircraft *v, const AirportFTAClass *apc) +{ + v->state = ENDLANDING; + AircraftLandAirplane(v); // maybe crash airplane + + /* check if the aircraft needs to be replaced or renewed and send it to a hangar if needed */ + if (v->NeedsAutomaticServicing()) { + Backup cur_company(_current_company, v->owner, FILE_LINE); + DoCommand(v->tile, v->index | DEPOT_SERVICE, 0, DC_EXEC, CMD_SEND_VEHICLE_TO_DEPOT); + cur_company.Restore(); + } +} + +static void AircraftEventHandler_HeliLanding(Aircraft *v, const AirportFTAClass *apc) +{ + v->state = HELIENDLANDING; + v->UpdateDeltaXY(INVALID_DIR); +} + +static void AircraftEventHandler_EndLanding(Aircraft *v, const AirportFTAClass *apc) +{ + /* next block busy, don't do a thing, just wait */ + if (AirportHasBlock(v, &apc->layout[v->pos], apc)) return; + + /* if going to terminal (OT_GOTO_STATION) choose one + * 1. in case all terminals are busy AirportFindFreeTerminal() returns false or + * 2. not going for terminal (but depot, no order), + * --> get out of the way to the hangar. */ + if (v->current_order.IsType(OT_GOTO_STATION)) { + if (AirportFindFreeTerminal(v, apc)) return; + } + v->state = HANGAR; + +} + +static void AircraftEventHandler_HeliEndLanding(Aircraft *v, const AirportFTAClass *apc) +{ + /* next block busy, don't do a thing, just wait */ + if (AirportHasBlock(v, &apc->layout[v->pos], apc)) return; + + /* if going to helipad (OT_GOTO_STATION) choose one. If airport doesn't have helipads, choose terminal + * 1. in case all terminals/helipads are busy (AirportFindFreeHelipad() returns false) or + * 2. not going for terminal (but depot, no order), + * --> get out of the way to the hangar IF there are terminals on the airport. + * --> else TAKEOFF + * the reason behind this is that if an airport has a terminal, it also has a hangar. Airplanes + * must go to a hangar. */ + if (v->current_order.IsType(OT_GOTO_STATION)) { + if (AirportFindFreeHelipad(v, apc)) return; + } + v->state = Station::Get(v->targetairport)->airport.HasHangar() ? HANGAR : HELITAKEOFF; +} + +/** + * Signature of the aircraft handler function. + * @param v Aircraft to handle. + * @param apc Airport state machine. + */ +typedef void AircraftStateHandler(Aircraft *v, const AirportFTAClass *apc); +/** Array of handler functions for each target of the aircraft. */ +static AircraftStateHandler * const _aircraft_state_handlers[] = { + AircraftEventHandler_General, // TO_ALL = 0 + AircraftEventHandler_InHangar, // HANGAR = 1 + AircraftEventHandler_AtTerminal, // TERM1 = 2 + AircraftEventHandler_AtTerminal, // TERM2 = 3 + AircraftEventHandler_AtTerminal, // TERM3 = 4 + AircraftEventHandler_AtTerminal, // TERM4 = 5 + AircraftEventHandler_AtTerminal, // TERM5 = 6 + AircraftEventHandler_AtTerminal, // TERM6 = 7 + AircraftEventHandler_AtTerminal, // HELIPAD1 = 8 + AircraftEventHandler_AtTerminal, // HELIPAD2 = 9 + AircraftEventHandler_TakeOff, // TAKEOFF = 10 + AircraftEventHandler_StartTakeOff, // STARTTAKEOFF = 11 + AircraftEventHandler_EndTakeOff, // ENDTAKEOFF = 12 + AircraftEventHandler_HeliTakeOff, // HELITAKEOFF = 13 + AircraftEventHandler_Flying, // FLYING = 14 + AircraftEventHandler_Landing, // LANDING = 15 + AircraftEventHandler_EndLanding, // ENDLANDING = 16 + AircraftEventHandler_HeliLanding, // HELILANDING = 17 + AircraftEventHandler_HeliEndLanding, // HELIENDLANDING = 18 + AircraftEventHandler_AtTerminal, // TERM7 = 19 + AircraftEventHandler_AtTerminal, // TERM8 = 20 + AircraftEventHandler_AtTerminal, // HELIPAD3 = 21 +}; + +static void AirportClearBlock(const Aircraft *v, const AirportFTAClass *apc) +{ + /* we have left the previous block, and entered the new one. Free the previous block */ + if (apc->layout[v->previous_pos].block != apc->layout[v->pos].block) { + Station *st = Station::Get(v->targetairport); + + CLRBITS(st->airport.flags, apc->layout[v->previous_pos].block); + } +} + +static void AirportGoToNextPosition(Aircraft *v) +{ + /* if aircraft is not in position, wait until it is */ + if (!AircraftController(v)) return; + + const AirportFTAClass *apc = Station::Get(v->targetairport)->airport.GetFTA(); + + AirportClearBlock(v, apc); + AirportMove(v, apc); // move aircraft to next position +} + +/* gets pos from vehicle and next orders */ +static bool AirportMove(Aircraft *v, const AirportFTAClass *apc) +{ + /* error handling */ + if (v->pos >= apc->nofelements) { + DEBUG(misc, 0, "[Ap] position %d is not valid for current airport. Max position is %d", v->pos, apc->nofelements-1); + assert(v->pos < apc->nofelements); + } + + const AirportFTA *current = &apc->layout[v->pos]; + /* we have arrived in an important state (eg terminal, hangar, etc.) */ + if (current->heading == v->state) { + byte prev_pos = v->pos; // location could be changed in state, so save it before-hand + byte prev_state = v->state; + _aircraft_state_handlers[v->state](v, apc); + if (v->state != FLYING) v->previous_pos = prev_pos; + if (v->state != prev_state || v->pos != prev_pos) UpdateAircraftCache(v); + return true; + } + + v->previous_pos = v->pos; // save previous location + + /* there is only one choice to move to */ + if (current->next == NULL) { + if (AirportSetBlocks(v, current, apc)) { + v->pos = current->next_position; + UpdateAircraftCache(v); + } // move to next position + return false; + } + + /* there are more choices to choose from, choose the one that + * matches our heading */ + do { + if (v->state == current->heading || current->heading == TO_ALL) { + if (AirportSetBlocks(v, current, apc)) { + v->pos = current->next_position; + UpdateAircraftCache(v); + } // move to next position + return false; + } + current = current->next; + } while (current != NULL); + + DEBUG(misc, 0, "[Ap] cannot move further on Airport! (pos %d state %d) for vehicle %d", v->pos, v->state, v->index); + NOT_REACHED(); +} + +/** returns true if the road ahead is busy, eg. you must wait before proceeding. */ +static bool AirportHasBlock(Aircraft *v, const AirportFTA *current_pos, const AirportFTAClass *apc) +{ + const AirportFTA *reference = &apc->layout[v->pos]; + const AirportFTA *next = &apc->layout[current_pos->next_position]; + + /* same block, then of course we can move */ + if (apc->layout[current_pos->position].block != next->block) { + const Station *st = Station::Get(v->targetairport); + uint64 airport_flags = next->block; + + /* check additional possible extra blocks */ + if (current_pos != reference && current_pos->block != NOTHING_block) { + airport_flags |= current_pos->block; + } + + if (st->airport.flags & airport_flags) { + v->cur_speed = 0; + v->subspeed = 0; + return true; + } + } + return false; +} + +/** + * "reserve" a block for the plane + * @param v airplane that requires the operation + * @param current_pos of the vehicle in the list of blocks + * @param apc airport on which block is requsted to be set + * @returns true on success. Eg, next block was free and we have occupied it + */ +static bool AirportSetBlocks(Aircraft *v, const AirportFTA *current_pos, const AirportFTAClass *apc) +{ + const AirportFTA *next = &apc->layout[current_pos->next_position]; + const AirportFTA *reference = &apc->layout[v->pos]; + + /* if the next position is in another block, check it and wait until it is free */ + if ((apc->layout[current_pos->position].block & next->block) != next->block) { + uint64 airport_flags = next->block; + /* search for all all elements in the list with the same state, and blocks != N + * this means more blocks should be checked/set */ + const AirportFTA *current = current_pos; + if (current == reference) current = current->next; + while (current != NULL) { + if (current->heading == current_pos->heading && current->block != 0) { + airport_flags |= current->block; + break; + } + current = current->next; + } + + /* if the block to be checked is in the next position, then exclude that from + * checking, because it has been set by the airplane before */ + if (current_pos->block == next->block) airport_flags ^= next->block; + + Station *st = Station::Get(v->targetairport); + if (st->airport.flags & airport_flags) { + v->cur_speed = 0; + v->subspeed = 0; + return false; + } + + if (next->block != NOTHING_block) { + SETBITS(st->airport.flags, airport_flags); // occupy next block + } + } + return true; +} + +/** + * Combination of aircraft state for going to a certain terminal and the + * airport flag for that terminal block. + */ +struct MovementTerminalMapping { + AirportMovementStates state; ///< Aircraft movement state when going to this terminal. + uint64 airport_flag; ///< Bitmask in the airport flags that need to be free for this terminal. +}; + +/** A list of all valid terminals and their associated blocks. */ +static const MovementTerminalMapping _airport_terminal_mapping[] = { + {TERM1, TERM1_block}, + {TERM2, TERM2_block}, + {TERM3, TERM3_block}, + {TERM4, TERM4_block}, + {TERM5, TERM5_block}, + {TERM6, TERM6_block}, + {TERM7, TERM7_block}, + {TERM8, TERM8_block}, + {HELIPAD1, HELIPAD1_block}, + {HELIPAD2, HELIPAD2_block}, + {HELIPAD3, HELIPAD3_block}, +}; + +/** + * Find a free terminal or helipad, and if available, assign it. + * @param v Aircraft looking for a free terminal or helipad. + * @param i First terminal to examine. + * @param last_terminal Terminal number to stop examining. + * @return A terminal or helipad has been found, and has been assigned to the aircraft. + */ +static bool FreeTerminal(Aircraft *v, byte i, byte last_terminal) +{ + assert(last_terminal <= lengthof(_airport_terminal_mapping)); + Station *st = Station::Get(v->targetairport); + for (; i < last_terminal; i++) { + if ((st->airport.flags & _airport_terminal_mapping[i].airport_flag) == 0) { + /* TERMINAL# HELIPAD# */ + v->state = _airport_terminal_mapping[i].state; // start moving to that terminal/helipad + SETBITS(st->airport.flags, _airport_terminal_mapping[i].airport_flag); // occupy terminal/helipad + return true; + } + } + return false; +} + +/** + * Get the number of terminals at the airport. + * @param afc Airport description. + * @return Number of terminals. + */ +static uint GetNumTerminals(const AirportFTAClass *apc) +{ + uint num = 0; + + for (uint i = apc->terminals[0]; i > 0; i--) num += apc->terminals[i]; + + return num; +} + +/** + * Find a free terminal, and assign it if available. + * @param v Aircraft to handle. + * @param apc Airport state machine. + * @return Found a free terminal and assigned it. + */ +static bool AirportFindFreeTerminal(Aircraft *v, const AirportFTAClass *apc) +{ + /* example of more terminalgroups + * {0,HANGAR,NOTHING_block,1}, {0,255,TERM_GROUP1_block,0}, {0,255,TERM_GROUP2_ENTER_block,1}, {0,0,N,1}, + * Heading 255 denotes a group. We see 2 groups here: + * 1. group 0 -- TERM_GROUP1_block (check block) + * 2. group 1 -- TERM_GROUP2_ENTER_block (check block) + * First in line is checked first, group 0. If the block (TERM_GROUP1_block) is free, it + * looks at the corresponding terminals of that group. If no free ones are found, other + * possible groups are checked (in this case group 1, since that is after group 0). If that + * fails, then attempt fails and plane waits + */ + if (apc->terminals[0] > 1) { + const Station *st = Station::Get(v->targetairport); + const AirportFTA *temp = apc->layout[v->pos].next; + + while (temp != NULL) { + if (temp->heading == 255) { + if (!(st->airport.flags & temp->block)) { + /* read which group do we want to go to? + * (the first free group) */ + uint target_group = temp->next_position + 1; + + /* at what terminal does the group start? + * that means, sum up all terminals of + * groups with lower number */ + uint group_start = 0; + for (uint i = 1; i < target_group; i++) { + group_start += apc->terminals[i]; + } + + uint group_end = group_start + apc->terminals[target_group]; + if (FreeTerminal(v, group_start, group_end)) return true; + } + } else { + /* once the heading isn't 255, we've exhausted the possible blocks. + * So we cannot move */ + return false; + } + temp = temp->next; + } + } + + /* if there is only 1 terminalgroup, all terminals are checked (starting from 0 to max) */ + return FreeTerminal(v, 0, GetNumTerminals(apc)); +} + +/** + * Find a free helipad, and assign it if available. + * @param v Aircraft to handle. + * @param apc Airport state machine. + * @return Found a free helipad and assigned it. + */ +static bool AirportFindFreeHelipad(Aircraft *v, const AirportFTAClass *apc) +{ + /* if an airport doesn't have helipads, use terminals */ + if (apc->num_helipads == 0) return AirportFindFreeTerminal(v, apc); + + /* only 1 helicoptergroup, check all helipads + * The blocks for helipads start after the last terminal (MAX_TERMINALS) */ + return FreeTerminal(v, MAX_TERMINALS, apc->num_helipads + MAX_TERMINALS); +} + +/** + * Handle the 'dest too far' flag and the corresponding news message for aircraft. + * @param v The aircraft. + * @param too_far True if the current destination is too far away. + */ +static void AircraftHandleDestTooFar(Aircraft *v, bool too_far) +{ + if (too_far) { + if (!HasBit(v->flags, VAF_DEST_TOO_FAR)) { + SetBit(v->flags, VAF_DEST_TOO_FAR); + SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); + AI::NewEvent(v->owner, new ScriptEventAircraftDestTooFar(v->index)); + if (v->owner == _local_company) { + /* Post a news message. */ + SetDParam(0, v->index); + AddVehicleAdviceNewsItem(STR_NEWS_AIRCRAFT_DEST_TOO_FAR, v->index); + } + } + return; + } + + if (HasBit(v->flags, VAF_DEST_TOO_FAR)) { + /* Not too far anymore, clear flag and message. */ + ClrBit(v->flags, VAF_DEST_TOO_FAR); + SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); + DeleteVehicleNews(v->index, STR_NEWS_AIRCRAFT_DEST_TOO_FAR); + } +} + +static bool AircraftEventHandler(Aircraft *v, int loop) +{ + if (v->vehstatus & VS_CRASHED) { + return HandleCrashedAircraft(v); + } + + if (v->vehstatus & VS_STOPPED) return true; + + v->HandleBreakdown(); + + HandleAircraftSmoke(v, loop != 0); + ProcessOrders(v); + v->HandleLoading(loop != 0); + + if (v->current_order.IsType(OT_LOADING) || v->current_order.IsType(OT_LEAVESTATION)) return true; + + if (v->state >= ENDTAKEOFF && v->state <= HELIENDLANDING) { + /* If we are flying, unconditionally clear the 'dest too far' state. */ + AircraftHandleDestTooFar(v, false); + } else if (v->acache.cached_max_range_sqr != 0) { + /* Check the distance to the next destination. This code works because the target + * airport is only updated after take off and not on the ground. */ + Station *cur_st = Station::GetIfValid(v->targetairport); + Station *next_st = v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_DEPOT) ? Station::GetIfValid(v->current_order.GetDestination()) : NULL; + + if (cur_st != NULL && cur_st->airport.tile != INVALID_TILE && next_st != NULL && next_st->airport.tile != INVALID_TILE) { + uint dist = DistanceSquare(cur_st->airport.tile, next_st->airport.tile); + AircraftHandleDestTooFar(v, dist > v->acache.cached_max_range_sqr); + } + } + + if (!HasBit(v->flags, VAF_DEST_TOO_FAR)) AirportGoToNextPosition(v); + + return true; +} + +bool Aircraft::Tick() +{ + if (!this->IsNormalAircraft()) return true; + + this->tick_counter++; + + if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++; + + if (this->subtype == AIR_HELICOPTER) HelicopterTickHandler(this); + + this->current_order_time++; + + for (uint i = 0; i != 2; i++) { + /* stop if the aircraft was deleted */ + if (!AircraftEventHandler(this, i)) return false; + } + + return true; +} + + +/** + * Returns aircraft's target station if v->target_airport + * is a valid station with airport. + * @param v vehicle to get target airport for + * @return pointer to target station, NULL if invalid + */ +Station *GetTargetAirportIfValid(const Aircraft *v) +{ + assert(v->type == VEH_AIRCRAFT); + + Station *st = Station::GetIfValid(v->targetairport); + if (st == NULL) return NULL; + + return st->airport.tile == INVALID_TILE ? NULL : st; +} + +/** + * Updates the status of the Aircraft heading or in the station + * @param st Station been updated + */ +void UpdateAirplanesOnNewStation(const Station *st) +{ + /* only 1 station is updated per function call, so it is enough to get entry_point once */ + const AirportFTAClass *ap = st->airport.GetFTA(); + Direction rotation = st->airport.tile == INVALID_TILE ? DIR_N : st->airport.rotation; + + Aircraft *v; + FOR_ALL_AIRCRAFT(v) { + if (!v->IsNormalAircraft() || v->targetairport != st->index) continue; + assert(v->state == FLYING); + v->pos = v->previous_pos = AircraftGetEntryPoint(v, ap, rotation); + UpdateAircraftCache(v); + } +} diff --git a/src/aircraft_gui.cpp b/src/aircraft_gui.cpp new file mode 100644 index 0000000..c3379d3 --- /dev/null +++ b/src/aircraft_gui.cpp @@ -0,0 +1,111 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file aircraft_gui.cpp The GUI of aircraft. */ + +#include "stdafx.h" +#include "aircraft.h" +#include "vehicle_gui.h" +#include "newgrf_engine.h" +#include "strings_func.h" +#include "vehicle_func.h" +#include "window_gui.h" +#include "spritecache.h" +#include "zoom_func.h" + +#include "table/strings.h" + +#include "safeguards.h" + +/** + * Draw the details for the given vehicle at the given position + * + * @param v current vehicle + * @param left The left most coordinate to draw + * @param right The right most coordinate to draw + * @param y The y coordinate + */ +void DrawAircraftDetails(const Aircraft *v, int left, int right, int y) +{ + int y_offset = (v->Next()->cargo_cap != 0) ? -(FONT_HEIGHT_NORMAL + 1): 0; + Money feeder_share = 0; + + for (const Aircraft *u = v; u != NULL; u = u->Next()) { + if (u->IsNormalAircraft()) { + SetDParam(0, u->engine_type); + SetDParam(1, u->build_year); + SetDParam(2, u->value); + DrawString(left, right, y, STR_VEHICLE_INFO_BUILT_VALUE); + + SetDParam(0, u->cargo_type); + SetDParam(1, u->cargo_cap); + SetDParam(2, u->Next()->cargo_type); + SetDParam(3, u->Next()->cargo_cap); + SetDParam(4, GetCargoSubtypeText(u)); + DrawString(left, right, y + FONT_HEIGHT_NORMAL, (u->Next()->cargo_cap != 0) ? STR_VEHICLE_INFO_CAPACITY_CAPACITY : STR_VEHICLE_INFO_CAPACITY); + } + + if (u->cargo_cap != 0) { + uint cargo_count = u->cargo.StoredCount(); + + y_offset += FONT_HEIGHT_NORMAL + 1; + if (cargo_count != 0) { + /* Cargo names (fix pluralness) */ + SetDParam(0, u->cargo_type); + SetDParam(1, cargo_count); + SetDParam(2, u->cargo.Source()); + DrawString(left, right, y + 2 * FONT_HEIGHT_NORMAL + 1 + y_offset, STR_VEHICLE_DETAILS_CARGO_FROM); + feeder_share += u->cargo.FeederShare(); + } + } + } + + SetDParam(0, feeder_share); + DrawString(left, right, y + 3 * FONT_HEIGHT_NORMAL + 3 + y_offset, STR_VEHICLE_INFO_FEEDER_CARGO_VALUE); +} + + +/** + * Draws an image of an aircraft + * @param v Front vehicle + * @param left The minimum horizontal position + * @param right The maximum horizontal position + * @param y Vertical position to draw at + * @param selection Selected vehicle to draw a frame around + */ +void DrawAircraftImage(const Vehicle *v, int left, int right, int y, VehicleID selection, EngineImageType image_type) +{ + bool rtl = _current_text_dir == TD_RTL; + + SpriteID sprite = v->GetImage(rtl ? DIR_E : DIR_W, image_type); + const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL); + + int width = UnScaleGUI(real_sprite->width); + int x_offs = UnScaleGUI(real_sprite->x_offs); + int x = rtl ? right - width - x_offs : left - x_offs; + bool helicopter = v->subtype == AIR_HELICOPTER; + + int y_offs = ScaleGUITrad(10); + int heli_offs = 0; + + PaletteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v); + DrawSprite(sprite, pal, x, y + y_offs); + if (helicopter) { + const Aircraft *a = Aircraft::From(v); + SpriteID rotor_sprite = GetCustomRotorSprite(a, true, image_type); + if (rotor_sprite == 0) rotor_sprite = SPR_ROTOR_STOPPED; + heli_offs = ScaleGUITrad(5); + DrawSprite(rotor_sprite, PAL_NONE, x, y + y_offs - heli_offs); + } + if (v->index == selection) { + x += x_offs; + y += UnScaleGUI(real_sprite->y_offs) + y_offs - heli_offs; + DrawFrameRect(x - 1, y - 1, x + width + 1, y + UnScaleGUI(real_sprite->height) + heli_offs + 1, COLOUR_WHITE, FR_BORDERONLY); + } +} diff --git a/src/airport.cpp b/src/airport.cpp new file mode 100644 index 0000000..a50c049 --- /dev/null +++ b/src/airport.cpp @@ -0,0 +1,235 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file airport.cpp Functions related to airports. */ + +#include "stdafx.h" +#include "station_base.h" +#include "table/strings.h" +#include "table/airport_movement.h" +#include "table/airporttile_ids.h" + +#include "safeguards.h" + + +/** + * Define a generic airport. + * @param name Suffix of the names of the airport data. + * @param terminals The terminals. + * @param num_helipads Number of heli pads. + * @param flags Information about the class of FTA. + * @param delta_z Height of the airport above the land. + */ +#define AIRPORT_GENERIC(name, terminals, num_helipads, flags, delta_z) \ + static AirportFTAClass _airportfta_ ## name(_airport_moving_data_ ## name, terminals, \ + num_helipads, _airport_entries_ ## name, flags, _airport_fta_ ## name, delta_z); + +/** + * Define an airport. + * @param name Suffix of the names of the airport data. + * @param num_helipads Number of heli pads. + * @param short_strip Airport has a short land/take-off strip. + */ +#define AIRPORT(name, num_helipads, short_strip) \ + AIRPORT_GENERIC(name, _airport_terminal_ ## name, num_helipads, AirportFTAClass::ALL | (short_strip ? AirportFTAClass::SHORT_STRIP : (AirportFTAClass::Flags)0), 0) + +/** + * Define a heliport. + * @param name Suffix of the names of the helipad data. + * @param num_helipads Number of heli pads. + * @param delta_z Height of the airport above the land. + */ +#define HELIPORT(name, num_helipads, delta_z) \ + AIRPORT_GENERIC(name, NULL, num_helipads, AirportFTAClass::HELICOPTERS, delta_z) + +AIRPORT(country, 0, true) +AIRPORT(city, 0, false) +HELIPORT(heliport, 1, 60) +AIRPORT(metropolitan, 0, false) +AIRPORT(international, 2, false) +AIRPORT(commuter, 2, true) +HELIPORT(helidepot, 1, 0) +AIRPORT(intercontinental, 2, false) +HELIPORT(helistation, 3, 0) +HELIPORT(oilrig, 1, 54) +AIRPORT_GENERIC(dummy, NULL, 0, AirportFTAClass::ALL, 0) + +#undef HELIPORT +#undef AIRPORT +#undef AIRPORT_GENERIC + +#include "table/airport_defaults.h" + + +static uint16 AirportGetNofElements(const AirportFTAbuildup *apFA); +static AirportFTA *AirportBuildAutomata(uint nofelements, const AirportFTAbuildup *apFA); + + +/** + * Rotate the airport moving data to another rotation. + * @param orig Pointer to the moving data to rotate. + * @param rotation How to rotate the moving data. + * @param num_tiles_x Number of tiles in x direction. + * @param num_tiles_y Number of tiles in y direction. + * @return The rotated moving data. + */ +AirportMovingData RotateAirportMovingData(const AirportMovingData *orig, Direction rotation, uint num_tiles_x, uint num_tiles_y) +{ + AirportMovingData amd; + amd.flag = orig->flag; + amd.direction = ChangeDir(orig->direction, (DirDiff)rotation); + switch (rotation) { + case DIR_N: + amd.x = orig->x; + amd.y = orig->y; + break; + + case DIR_E: + amd.x = orig->y; + amd.y = num_tiles_y * TILE_SIZE - orig->x - 1; + break; + + case DIR_S: + amd.x = num_tiles_x * TILE_SIZE - orig->x - 1; + amd.y = num_tiles_y * TILE_SIZE - orig->y - 1; + break; + + case DIR_W: + amd.x = num_tiles_x * TILE_SIZE - orig->y - 1; + amd.y = orig->x; + break; + + default: NOT_REACHED(); + } + return amd; +} + +AirportFTAClass::AirportFTAClass( + const AirportMovingData *moving_data_, + const byte *terminals_, + const byte num_helipads_, + const byte *entry_points_, + Flags flags_, + const AirportFTAbuildup *apFA, + byte delta_z_ +) : + moving_data(moving_data_), + terminals(terminals_), + num_helipads(num_helipads_), + flags(flags_), + nofelements(AirportGetNofElements(apFA)), + entry_points(entry_points_), + delta_z(delta_z_) +{ + /* Build the state machine itself */ + this->layout = AirportBuildAutomata(this->nofelements, apFA); +} + +AirportFTAClass::~AirportFTAClass() +{ + for (uint i = 0; i < nofelements; i++) { + AirportFTA *current = layout[i].next; + while (current != NULL) { + AirportFTA *next = current->next; + free(current); + current = next; + } + } + free(layout); +} + +/** + * Get the number of elements of a source Airport state automata + * Since it is actually just a big array of AirportFTA types, we only + * know one element from the other by differing 'position' identifiers + */ +static uint16 AirportGetNofElements(const AirportFTAbuildup *apFA) +{ + uint16 nofelements = 0; + int temp = apFA[0].position; + + for (uint i = 0; i < MAX_ELEMENTS; i++) { + if (temp != apFA[i].position) { + nofelements++; + temp = apFA[i].position; + } + if (apFA[i].position == MAX_ELEMENTS) break; + } + return nofelements; +} + +/** + * Construct the FTA given a description. + * @param nofelements The number of elements in the FTA. + * @param apFA The description of the FTA. + * @return The FTA describing the airport. + */ +static AirportFTA *AirportBuildAutomata(uint nofelements, const AirportFTAbuildup *apFA) +{ + AirportFTA *FAutomata = MallocT(nofelements); + uint16 internalcounter = 0; + + for (uint i = 0; i < nofelements; i++) { + AirportFTA *current = &FAutomata[i]; + current->position = apFA[internalcounter].position; + current->heading = apFA[internalcounter].heading; + current->block = apFA[internalcounter].block; + current->next_position = apFA[internalcounter].next; + + /* outgoing nodes from the same position, create linked list */ + while (current->position == apFA[internalcounter + 1].position) { + AirportFTA *newNode = MallocT(1); + + newNode->position = apFA[internalcounter + 1].position; + newNode->heading = apFA[internalcounter + 1].heading; + newNode->block = apFA[internalcounter + 1].block; + newNode->next_position = apFA[internalcounter + 1].next; + /* create link */ + current->next = newNode; + current = current->next; + internalcounter++; + } + current->next = NULL; + internalcounter++; + } + return FAutomata; +} + +/** + * Get the finite state machine of an airport type. + * @param airport_type %Airport type to query FTA from. @see AirportTypes + * @return Finite state machine of the airport. + */ +const AirportFTAClass *GetAirport(const byte airport_type) +{ + if (airport_type == AT_DUMMY) return &_airportfta_dummy; + return AirportSpec::Get(airport_type)->fsm; +} + +/** + * Get the vehicle position when an aircraft is build at the given tile + * @param hangar_tile The tile on which the vehicle is build + * @return The position (index in airport node array) where the aircraft ends up + */ +byte GetVehiclePosOnBuild(TileIndex hangar_tile) +{ + const Station *st = Station::GetByTile(hangar_tile); + const AirportFTAClass *apc = st->airport.GetFTA(); + /* When we click on hangar we know the tile it is on. By that we know + * its position in the array of depots the airport has.....we can search + * layout for #th position of depot. Since layout must start with a listing + * of all depots, it is simple */ + for (uint i = 0;; i++) { + if (st->airport.GetHangarTile(i) == hangar_tile) { + assert(apc->layout[i].heading == HANGAR); + return apc->layout[i].position; + } + } + NOT_REACHED(); +} diff --git a/src/airport.h b/src/airport.h new file mode 100644 index 0000000..31c68ef --- /dev/null +++ b/src/airport.h @@ -0,0 +1,202 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file airport.h Various declarations for airports */ + +#ifndef AIRPORT_H +#define AIRPORT_H + +#include "direction_type.h" +#include "tile_type.h" + +/** Some airport-related constants */ +static const uint MAX_TERMINALS = 8; ///< maximum number of terminals per airport +static const uint MAX_HELIPADS = 3; ///< maximum number of helipads per airport +static const uint MAX_ELEMENTS = 255; ///< maximum number of aircraft positions at airport + +static const uint NUM_AIRPORTTILES_PER_GRF = 255; ///< Number of airport tiles per NewGRF; limited to 255 to allow extending Action3 with an extended byte later on. + +static const uint NUM_AIRPORTTILES = 256; ///< Total number of airport tiles. +static const uint NEW_AIRPORTTILE_OFFSET = 74; ///< offset of first newgrf airport tile +static const uint INVALID_AIRPORTTILE = NUM_AIRPORTTILES; ///< id for an invalid airport tile + +/** Airport types */ +enum AirportTypes { + AT_SMALL = 0, ///< Small airport. + AT_LARGE = 1, ///< Large airport. + AT_HELIPORT = 2, ///< Heli port. + AT_METROPOLITAN = 3, ///< Metropolitan airport. + AT_INTERNATIONAL = 4, ///< International airport. + AT_COMMUTER = 5, ///< Commuter airport. + AT_HELIDEPOT = 6, ///< Heli depot. + AT_INTERCON = 7, ///< Intercontinental airport. + AT_HELISTATION = 8, ///< Heli station airport. + AT_OILRIG = 9, ///< Oilrig airport. + NEW_AIRPORT_OFFSET = 10, ///< Number of the first newgrf airport. + NUM_AIRPORTS_PER_GRF = 128, ///< Maximal number of airports per NewGRF. + NUM_AIRPORTS = 128, ///< Maximal number of airports in total. + AT_INVALID = 254, ///< Invalid airport. + AT_DUMMY = 255, ///< Dummy airport. +}; + +/** Flags for airport movement data. */ +enum AirportMovingDataFlags { + AMED_NOSPDCLAMP = 1 << 0, ///< No speed restrictions. + AMED_TAKEOFF = 1 << 1, ///< Takeoff movement. + AMED_SLOWTURN = 1 << 2, ///< Turn slowly (mostly used in the air). + AMED_LAND = 1 << 3, ///< Landing onto landing strip. + AMED_EXACTPOS = 1 << 4, ///< Go exactly to the destination coordinates. + AMED_BRAKE = 1 << 5, ///< Taxiing at the airport. + AMED_HELI_RAISE = 1 << 6, ///< Helicopter take-off. + AMED_HELI_LOWER = 1 << 7, ///< Helicopter landing. + AMED_HOLD = 1 << 8, ///< Holding pattern movement (above the airport). +}; + +/** Movement States on Airports (headings target) */ +enum AirportMovementStates { + TO_ALL = 0, ///< Go in this direction for every target. + HANGAR = 1, ///< Heading for hangar. + TERM1 = 2, ///< Heading for terminal 1. + TERM2 = 3, ///< Heading for terminal 2. + TERM3 = 4, ///< Heading for terminal 3. + TERM4 = 5, ///< Heading for terminal 4. + TERM5 = 6, ///< Heading for terminal 5. + TERM6 = 7, ///< Heading for terminal 6. + HELIPAD1 = 8, ///< Heading for helipad 1. + HELIPAD2 = 9, ///< Heading for helipad 2. + TAKEOFF = 10, ///< Airplane wants to leave the airport. + STARTTAKEOFF = 11, ///< Airplane has arrived at a runway for take-off. + ENDTAKEOFF = 12, ///< Airplane has reached end-point of the take-off runway. + HELITAKEOFF = 13, ///< Helicopter wants to leave the airport. + FLYING = 14, ///< %Vehicle is flying in the air. + LANDING = 15, ///< Airplane wants to land. + ENDLANDING = 16, ///< Airplane wants to finish landing. + HELILANDING = 17, ///< Helicopter wants to land. + HELIENDLANDING = 18, ///< Helicopter wants to finish landing. + TERM7 = 19, ///< Heading for terminal 7. + TERM8 = 20, ///< Heading for terminal 8. + HELIPAD3 = 21, ///< Heading for helipad 3. + MAX_HEADINGS = 21, ///< Last valid target to head for. +}; + +/** Movement Blocks on Airports blocks (eg_airport_flags). */ +static const uint64 + TERM1_block = 1ULL << 0, ///< Block belonging to terminal 1. + TERM2_block = 1ULL << 1, ///< Block belonging to terminal 2. + TERM3_block = 1ULL << 2, ///< Block belonging to terminal 3. + TERM4_block = 1ULL << 3, ///< Block belonging to terminal 4. + TERM5_block = 1ULL << 4, ///< Block belonging to terminal 5. + TERM6_block = 1ULL << 5, ///< Block belonging to terminal 6. + HELIPAD1_block = 1ULL << 6, ///< Block belonging to helipad 1. + HELIPAD2_block = 1ULL << 7, ///< Block belonging to helipad 2. + RUNWAY_IN_OUT_block = 1ULL << 8, + RUNWAY_IN_block = 1ULL << 8, + AIRPORT_BUSY_block = 1ULL << 8, + RUNWAY_OUT_block = 1ULL << 9, + TAXIWAY_BUSY_block = 1ULL << 10, + OUT_WAY_block = 1ULL << 11, + IN_WAY_block = 1ULL << 12, + AIRPORT_ENTRANCE_block = 1ULL << 13, + TERM_GROUP1_block = 1ULL << 14, + TERM_GROUP2_block = 1ULL << 15, + HANGAR2_AREA_block = 1ULL << 16, + TERM_GROUP2_ENTER1_block = 1ULL << 17, + TERM_GROUP2_ENTER2_block = 1ULL << 18, + TERM_GROUP2_EXIT1_block = 1ULL << 19, + TERM_GROUP2_EXIT2_block = 1ULL << 20, + PRE_HELIPAD_block = 1ULL << 21, + + /* blocks for new airports */ + TERM7_block = 1ULL << 22, ///< Block belonging to terminal 7. + TERM8_block = 1ULL << 23, ///< Block belonging to terminal 8. + HELIPAD3_block = 1ULL << 24, ///< Block belonging to helipad 3. + HANGAR1_AREA_block = 1ULL << 26, + OUT_WAY2_block = 1ULL << 27, + IN_WAY2_block = 1ULL << 28, + RUNWAY_IN2_block = 1ULL << 29, + RUNWAY_OUT2_block = 1ULL << 10, ///< @note re-uses #TAXIWAY_BUSY_block + HELIPAD_GROUP_block = 1ULL << 13, ///< @note re-uses #AIRPORT_ENTRANCE_block + OUT_WAY_block2 = 1ULL << 31, + /* end of new blocks */ + + NOTHING_block = 1ULL << 30, + AIRPORT_CLOSED_block = 1ULL << 63; ///< Dummy block for indicating a closed airport. + +/** A single location on an airport where aircraft can move to. */ +struct AirportMovingData { + int16 x; ///< x-coordinate of the destination. + int16 y; ///< y-coordinate of the destination. + uint16 flag; ///< special flags when moving towards the destination. + DirectionByte direction; ///< Direction to turn the aircraft after reaching the destination. +}; + +AirportMovingData RotateAirportMovingData(const AirportMovingData *orig, Direction rotation, uint num_tiles_x, uint num_tiles_y); + +struct AirportFTAbuildup; + +/** Finite sTate mAchine (FTA) of an airport. */ +struct AirportFTAClass { +public: + /** Bitmask of airport flags. */ + enum Flags { + AIRPLANES = 0x1, ///< Can planes land on this airport type? + HELICOPTERS = 0x2, ///< Can helicopters land on this airport type? + ALL = AIRPLANES | HELICOPTERS, ///< Mask to check for both planes and helicopters. + SHORT_STRIP = 0x4, ///< This airport has a short landing strip, dangerous for fast aircraft. + }; + + AirportFTAClass( + const AirportMovingData *moving_data, + const byte *terminals, + const byte num_helipads, + const byte *entry_points, + Flags flags, + const AirportFTAbuildup *apFA, + byte delta_z + ); + + ~AirportFTAClass(); + + /** + * Get movement data at a position. + * @param position Element number to get movement data about. + * @return Pointer to the movement data. + */ + const AirportMovingData *MovingData(byte position) const + { + assert(position < nofelements); + return &moving_data[position]; + } + + const AirportMovingData *moving_data; ///< Movement data. + struct AirportFTA *layout; ///< state machine for airport + const byte *terminals; ///< %Array with the number of terminal groups, followed by the number of terminals in each group. + const byte num_helipads; ///< Number of helipads on this airport. When 0 helicopters will go to normal terminals. + Flags flags; ///< Flags for this airport type. + byte nofelements; ///< number of positions the airport consists of + const byte *entry_points; ///< when an airplane arrives at this airport, enter it at position entry_point, index depends on direction + byte delta_z; ///< Z adjustment for helicopter pads +}; + +DECLARE_ENUM_AS_BIT_SET(AirportFTAClass::Flags) + + +/** Internal structure used in openttd - Finite sTate mAchine --> FTA */ +struct AirportFTA { + AirportFTA *next; ///< possible extra movement choices from this position + uint64 block; ///< 64 bit blocks (st->airport.flags), should be enough for the most complex airports + byte position; ///< the position that an airplane is at + byte next_position; ///< next position from this position + byte heading; ///< heading (current orders), guiding an airplane to its target on an airport +}; + +const AirportFTAClass *GetAirport(const byte airport_type); +byte GetVehiclePosOnBuild(TileIndex hangar_tile); + +#endif /* AIRPORT_H */ diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp new file mode 100644 index 0000000..6437f23 --- /dev/null +++ b/src/airport_gui.cpp @@ -0,0 +1,605 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file airport_gui.cpp The GUI for airports. */ + +#include "stdafx.h" +#include "window_gui.h" +#include "station_gui.h" +#include "terraform_gui.h" +#include "sound_func.h" +#include "window_func.h" +#include "strings_func.h" +#include "viewport_func.h" +#include "company_func.h" +#include "tilehighlight_func.h" +#include "company_base.h" +#include "station_type.h" +#include "newgrf_airport.h" +#include "newgrf_callbacks.h" +#include "widgets/dropdown_type.h" +#include "core/geometry_func.hpp" +#include "hotkeys.h" +#include "vehicle_func.h" +#include "gui.h" + +#include "widgets/airport_widget.h" + +#include "safeguards.h" + + +static AirportClassID _selected_airport_class; ///< the currently visible airport class +static int _selected_airport_index; ///< the index of the selected airport in the current class or -1 +static byte _selected_airport_layout; ///< selected airport layout number. + +static void ShowBuildAirportPicker(Window *parent); + +SpriteID GetCustomAirportSprite(const AirportSpec *as, byte layout); + +void CcBuildAirport(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) +{ + if (result.Failed()) return; + + if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT_OTHER, tile); + if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); +} + +/** + * Place an airport. + * @param tile Position to put the new airport. + */ +static void PlaceAirport(TileIndex tile) +{ + if (_selected_airport_index == -1) return; + uint32 p2 = _ctrl_pressed; + SB(p2, 16, 16, INVALID_STATION); // no station to join + + uint32 p1 = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index)->GetIndex(); + p1 |= _selected_airport_layout << 8; + CommandContainer cmdcont = { tile, p1, p2, CMD_BUILD_AIRPORT | CMD_MSG(STR_ERROR_CAN_T_BUILD_AIRPORT_HERE), CcBuildAirport, "" }; + ShowSelectStationIfNeeded(cmdcont, TileArea(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE)); +} + +/** Airport build toolbar window handler. */ +struct BuildAirToolbarWindow : Window { + int last_user_action; // Last started user action. + + BuildAirToolbarWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) + { + this->InitNested(window_number); + if (_settings_client.gui.link_terraform_toolbar) ShowTerraformToolbar(this); + this->last_user_action = WIDGET_LIST_END; + } + + ~BuildAirToolbarWindow() + { + if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false); + } + + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (!gui_scope) return; + + if (!CanBuildVehicleInfrastructure(VEH_AIRCRAFT)) delete this; + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_AT_AIRPORT: + if (HandlePlacePushButton(this, WID_AT_AIRPORT, SPR_CURSOR_AIRPORT, HT_RECT)) { + ShowBuildAirportPicker(this); + this->last_user_action = widget; + } + break; + + case WID_AT_DEMOLISH: + HandlePlacePushButton(this, WID_AT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL); + this->last_user_action = widget; + break; + + default: break; + } + } + + + virtual void OnPlaceObject(Point pt, TileIndex tile) + { + switch (this->last_user_action) { + case WID_AT_AIRPORT: + PlaceAirport(tile); + break; + + case WID_AT_DEMOLISH: + PlaceProc_DemolishArea(tile); + break; + + default: NOT_REACHED(); + } + } + + virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) + { + VpSelectTilesWithMethod(pt.x, pt.y, select_method); + } + + virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) + { + if (pt.x != -1 && select_proc == DDSP_DEMOLISH_AREA) { + GUIPlaceProcDragXY(select_proc, start_tile, end_tile); + } + } + + virtual void OnPlaceObjectAbort() + { + this->RaiseButtons(); + + DeleteWindowById(WC_BUILD_STATION, TRANSPORT_AIR); + DeleteWindowById(WC_SELECT_STATION, 0); + } + + static HotkeyList hotkeys; +}; + +/** + * Handler for global hotkeys of the BuildAirToolbarWindow. + * @param hotkey Hotkey + * @return ES_HANDLED if hotkey was accepted. + */ +static EventState AirportToolbarGlobalHotkeys(int hotkey) +{ + if (_game_mode != GM_NORMAL || !CanBuildVehicleInfrastructure(VEH_AIRCRAFT)) return ES_NOT_HANDLED; + Window *w = ShowBuildAirToolbar(); + if (w == NULL) return ES_NOT_HANDLED; + return w->OnHotkey(hotkey); +} + +static Hotkey airtoolbar_hotkeys[] = { + Hotkey('1', "airport", WID_AT_AIRPORT), + Hotkey('2', "demolish", WID_AT_DEMOLISH), + HOTKEY_LIST_END +}; +HotkeyList BuildAirToolbarWindow::hotkeys("airtoolbar", airtoolbar_hotkeys, AirportToolbarGlobalHotkeys); + +static const NWidgetPart _nested_air_toolbar_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_TOOLBAR_AIRCRAFT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_AT_AIRPORT), SetFill(0, 1), SetMinimalSize(42, 22), SetDataTip(SPR_IMG_AIRPORT, STR_TOOLBAR_AIRCRAFT_BUILD_AIRPORT_TOOLTIP), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(4, 22), SetFill(1, 1), EndContainer(), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_AT_DEMOLISH), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), + EndContainer(), +}; + +static WindowDesc _air_toolbar_desc( + WDP_ALIGN_TOOLBAR, "toolbar_air", 0, 0, + WC_BUILD_TOOLBAR, WC_NONE, + WDF_CONSTRUCTION, + _nested_air_toolbar_widgets, lengthof(_nested_air_toolbar_widgets), + &BuildAirToolbarWindow::hotkeys +); + +/** + * Open the build airport toolbar window + * + * If the terraform toolbar is linked to the toolbar, that window is also opened. + * + * @return newly opened airport toolbar, or NULL if the toolbar could not be opened. + */ +Window *ShowBuildAirToolbar() +{ + if (!Company::IsValidID(_local_company)) return NULL; + + DeleteWindowByClass(WC_BUILD_TOOLBAR); + return AllocateWindowDescFront(&_air_toolbar_desc, TRANSPORT_AIR); +} + +class BuildAirportWindow : public PickerWindowBase { + SpriteID preview_sprite; ///< Cached airport preview sprite. + int line_height; + Scrollbar *vscroll; + + /** Build a dropdown list of available airport classes */ + static DropDownList *BuildAirportClassDropDown() + { + DropDownList *list = new DropDownList(); + + for (uint i = 0; i < AirportClass::GetClassCount(); i++) { + *list->Append() = new DropDownListStringItem(AirportClass::Get((AirportClassID)i)->name, i, false); + } + + return list; + } + +public: + BuildAirportWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent) + { + this->CreateNestedTree(); + + this->vscroll = this->GetScrollbar(WID_AP_SCROLLBAR); + this->vscroll->SetCapacity(5); + this->vscroll->SetPosition(0); + + this->FinishInitNested(TRANSPORT_AIR); + + this->SetWidgetLoweredState(WID_AP_BTN_DONTHILIGHT, !_settings_client.gui.station_show_coverage); + this->SetWidgetLoweredState(WID_AP_BTN_DOHILIGHT, _settings_client.gui.station_show_coverage); + this->OnInvalidateData(); + + /* Ensure airport class is valid (changing NewGRFs). */ + _selected_airport_class = Clamp(_selected_airport_class, APC_BEGIN, (AirportClassID)(AirportClass::GetClassCount() - 1)); + const AirportClass *ac = AirportClass::Get(_selected_airport_class); + this->vscroll->SetCount(ac->GetSpecCount()); + + /* Ensure the airport index is valid for this class (changing NewGRFs). */ + _selected_airport_index = Clamp(_selected_airport_index, -1, ac->GetSpecCount() - 1); + + /* Only when no valid airport was selected, we want to select the first airport. */ + bool selectFirstAirport = true; + if (_selected_airport_index != -1) { + const AirportSpec *as = ac->GetSpec(_selected_airport_index); + if (as->IsAvailable()) { + /* Ensure the airport layout is valid. */ + _selected_airport_layout = Clamp(_selected_airport_layout, 0, as->num_table - 1); + selectFirstAirport = false; + this->UpdateSelectSize(); + } + } + + if (selectFirstAirport) this->SelectFirstAvailableAirport(true); + } + + virtual ~BuildAirportWindow() + { + DeleteWindowById(WC_SELECT_STATION, 0); + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_AP_CLASS_DROPDOWN: + SetDParam(0, AirportClass::Get(_selected_airport_class)->name); + break; + + case WID_AP_LAYOUT_NUM: + SetDParam(0, STR_EMPTY); + if (_selected_airport_index != -1) { + const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index); + StringID string = GetAirportTextCallback(as, _selected_airport_layout, CBID_AIRPORT_LAYOUT_NAME); + if (string != STR_UNDEFINED) { + SetDParam(0, string); + } else if (as->num_table > 1) { + SetDParam(0, STR_STATION_BUILD_AIRPORT_LAYOUT_NAME); + SetDParam(1, _selected_airport_layout + 1); + } + } + break; + + default: break; + } + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_AP_CLASS_DROPDOWN: { + Dimension d = {0, 0}; + for (uint i = 0; i < AirportClass::GetClassCount(); i++) { + SetDParam(0, AirportClass::Get((AirportClassID)i)->name); + d = maxdim(d, GetStringBoundingBox(STR_BLACK_STRING)); + } + d.width += padding.width; + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + + case WID_AP_AIRPORT_LIST: { + for (int i = 0; i < NUM_AIRPORTS; i++) { + const AirportSpec *as = AirportSpec::Get(i); + if (!as->enabled) continue; + + size->width = max(size->width, GetStringBoundingBox(as->name).width); + } + + this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; + size->height = 5 * this->line_height; + break; + } + + case WID_AP_AIRPORT_SPRITE: + for (int i = 0; i < NUM_AIRPORTS; i++) { + const AirportSpec *as = AirportSpec::Get(i); + if (!as->enabled) continue; + for (byte layout = 0; layout < as->num_table; layout++) { + SpriteID sprite = GetCustomAirportSprite(as, layout); + if (sprite != 0) { + Dimension d = GetSpriteSize(sprite); + d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + *size = maxdim(d, *size); + } + } + } + break; + + case WID_AP_EXTRA_TEXT: + for (int i = NEW_AIRPORT_OFFSET; i < NUM_AIRPORTS; i++) { + const AirportSpec *as = AirportSpec::Get(i); + if (!as->enabled) continue; + for (byte layout = 0; layout < as->num_table; layout++) { + StringID string = GetAirportTextCallback(as, layout, CBID_AIRPORT_ADDITIONAL_TEXT); + if (string == STR_UNDEFINED) continue; + + /* STR_BLACK_STRING is used to start the string with {BLACK} */ + SetDParam(0, string); + Dimension d = GetStringMultiLineBoundingBox(STR_BLACK_STRING, *size); + *size = maxdim(d, *size); + } + } + break; + + default: break; + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_AP_AIRPORT_LIST: { + int y = r.top; + AirportClass *apclass = AirportClass::Get(_selected_airport_class); + for (uint i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < apclass->GetSpecCount(); i++) { + const AirportSpec *as = apclass->GetSpec(i); + if (!as->IsAvailable()) { + GfxFillRect(r.left + 1, y + 1, r.right - 1, y + this->line_height - 2, PC_BLACK, FILLRECT_CHECKER); + } + DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, y + WD_MATRIX_TOP, as->name, ((int)i == _selected_airport_index) ? TC_WHITE : TC_BLACK); + y += this->line_height; + } + break; + } + + case WID_AP_AIRPORT_SPRITE: + if (this->preview_sprite != 0) { + Dimension d = GetSpriteSize(this->preview_sprite); + DrawSprite(this->preview_sprite, COMPANY_SPRITE_COLOUR(_local_company), (r.left + r.right - d.width) / 2, (r.top + r.bottom - d.height) / 2); + } + break; + + case WID_AP_EXTRA_TEXT: + if (_selected_airport_index != -1) { + const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index); + StringID string = GetAirportTextCallback(as, _selected_airport_layout, CBID_AIRPORT_ADDITIONAL_TEXT); + if (string != STR_UNDEFINED) { + SetDParam(0, string); + DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_BLACK_STRING); + } + } + break; + } + } + + virtual void OnPaint() + { + this->DrawWidgets(); + + uint16 top = this->GetWidget(WID_AP_BTN_DOHILIGHT)->pos_y + this->GetWidget(WID_AP_BTN_DOHILIGHT)->current_y + WD_PAR_VSEP_NORMAL; + NWidgetBase *panel_nwi = this->GetWidget(WID_AP_BOTTOMPANEL); + + int right = panel_nwi->pos_x + panel_nwi->current_x; + int bottom = panel_nwi->pos_y + panel_nwi->current_y; + + if (_selected_airport_index != -1) { + const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index); + int rad = _settings_game.station.modified_catchment ? as->catchment : (uint)CA_UNMODIFIED; + + /* only show the station (airport) noise, if the noise option is activated */ + if (_settings_game.economy.station_noise_level) { + /* show the noise of the selected airport */ + SetDParam(0, as->noise_level); + DrawString(panel_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, STR_STATION_BUILD_NOISE); + top += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; + } + + /* strings such as 'Size' and 'Coverage Area' */ + top = DrawStationCoverageAreaText(panel_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, SCT_ALL, rad, false) + WD_PAR_VSEP_NORMAL; + top = DrawStationCoverageAreaText(panel_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, SCT_ALL, rad, true) + WD_PAR_VSEP_NORMAL; + } + + /* Resize background if the window is too small. + * Never make the window smaller to avoid oscillating if the size change affects the acceptance. + * (This is the case, if making the window bigger moves the mouse into the window.) */ + if (top > bottom) { + ResizeWindow(this, 0, top - bottom, false); + } + } + + void SelectOtherAirport(int airport_index) + { + _selected_airport_index = airport_index; + _selected_airport_layout = 0; + + this->UpdateSelectSize(); + this->SetDirty(); + } + + void UpdateSelectSize() + { + if (_selected_airport_index == -1) { + SetTileSelectSize(1, 1); + this->DisableWidget(WID_AP_LAYOUT_DECREASE); + this->DisableWidget(WID_AP_LAYOUT_INCREASE); + } else { + const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index); + int w = as->size_x; + int h = as->size_y; + Direction rotation = as->rotation[_selected_airport_layout]; + if (rotation == DIR_E || rotation == DIR_W) Swap(w, h); + SetTileSelectSize(w, h); + + this->preview_sprite = GetCustomAirportSprite(as, _selected_airport_layout); + + this->SetWidgetDisabledState(WID_AP_LAYOUT_DECREASE, _selected_airport_layout == 0); + this->SetWidgetDisabledState(WID_AP_LAYOUT_INCREASE, _selected_airport_layout + 1 >= as->num_table); + + int rad = _settings_game.station.modified_catchment ? as->catchment : (uint)CA_UNMODIFIED; + if (_settings_client.gui.station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad); + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_AP_CLASS_DROPDOWN: + ShowDropDownList(this, BuildAirportClassDropDown(), _selected_airport_class, WID_AP_CLASS_DROPDOWN); + break; + + case WID_AP_AIRPORT_LIST: { + int num_clicked = this->vscroll->GetPosition() + (pt.y - this->nested_array[widget]->pos_y) / this->line_height; + if (num_clicked >= this->vscroll->GetCount()) break; + const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(num_clicked); + if (as->IsAvailable()) this->SelectOtherAirport(num_clicked); + break; + } + + case WID_AP_BTN_DONTHILIGHT: case WID_AP_BTN_DOHILIGHT: + _settings_client.gui.station_show_coverage = (widget != WID_AP_BTN_DONTHILIGHT); + this->SetWidgetLoweredState(WID_AP_BTN_DONTHILIGHT, !_settings_client.gui.station_show_coverage); + this->SetWidgetLoweredState(WID_AP_BTN_DOHILIGHT, _settings_client.gui.station_show_coverage); + this->SetDirty(); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + this->UpdateSelectSize(); + break; + + case WID_AP_LAYOUT_DECREASE: + _selected_airport_layout--; + this->UpdateSelectSize(); + this->SetDirty(); + break; + + case WID_AP_LAYOUT_INCREASE: + _selected_airport_layout++; + this->UpdateSelectSize(); + this->SetDirty(); + break; + } + } + + /** + * Select the first available airport. + * @param change_class If true, change the class if no airport in the current + * class is available. + */ + void SelectFirstAvailableAirport(bool change_class) + { + /* First try to select an airport in the selected class. */ + AirportClass *sel_apclass = AirportClass::Get(_selected_airport_class); + for (uint i = 0; i < sel_apclass->GetSpecCount(); i++) { + const AirportSpec *as = sel_apclass->GetSpec(i); + if (as->IsAvailable()) { + this->SelectOtherAirport(i); + return; + } + } + if (change_class) { + /* If that fails, select the first available airport + * from a random class. */ + for (AirportClassID j = APC_BEGIN; j < APC_MAX; j++) { + AirportClass *apclass = AirportClass::Get(j); + for (uint i = 0; i < apclass->GetSpecCount(); i++) { + const AirportSpec *as = apclass->GetSpec(i); + if (as->IsAvailable()) { + _selected_airport_class = j; + this->SelectOtherAirport(i); + return; + } + } + } + } + /* If all airports are unavailable, select nothing. */ + this->SelectOtherAirport(-1); + } + + virtual void OnDropdownSelect(int widget, int index) + { + assert(widget == WID_AP_CLASS_DROPDOWN); + _selected_airport_class = (AirportClassID)index; + this->vscroll->SetCount(AirportClass::Get(_selected_airport_class)->GetSpecCount()); + this->SelectFirstAvailableAirport(false); + } + + virtual void OnTick() + { + CheckRedrawStationCoverage(this); + } +}; + +static const NWidgetPart _nested_build_airport_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_AIRPORT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetFill(1, 0), SetPIP(2, 0, 2), + NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_AIRPORT_CLASS_LABEL, STR_NULL), SetFill(1, 0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_AP_CLASS_DROPDOWN), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_STATION_BUILD_AIRPORT_TOOLTIP), + NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_AP_AIRPORT_SPRITE), SetFill(1, 0), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_AP_AIRPORT_LIST), SetFill(1, 0), SetMatrixDataTip(1, 5, STR_STATION_BUILD_AIRPORT_TOOLTIP), SetScrollbar(WID_AP_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_AP_SCROLLBAR), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_AP_LAYOUT_DECREASE), SetMinimalSize(12, 0), SetDataTip(AWV_DECREASE, STR_NULL), + NWidget(WWT_LABEL, COLOUR_GREY, WID_AP_LAYOUT_NUM), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NULL), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_AP_LAYOUT_INCREASE), SetMinimalSize(12, 0), SetDataTip(AWV_INCREASE, STR_NULL), + EndContainer(), + NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_AP_EXTRA_TEXT), SetFill(1, 0), SetMinimalSize(150, 0), + EndContainer(), + /* Bottom panel. */ + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_AP_BOTTOMPANEL), SetPIP(2, 2, 2), + NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), SetFill(1, 0), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_SPACER), SetMinimalSize(14, 0), SetFill(1, 0), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AP_BTN_DONTHILIGHT), SetMinimalSize(60, 12), SetFill(1, 0), + SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AP_BTN_DOHILIGHT), SetMinimalSize(60, 12), SetFill(1, 0), + SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(14, 0), SetFill(1, 0), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 10), SetResize(0, 1), SetFill(1, 0), + EndContainer(), +}; + +static WindowDesc _build_airport_desc( + WDP_AUTO, "build_station_air", 0, 0, + WC_BUILD_STATION, WC_BUILD_TOOLBAR, + WDF_CONSTRUCTION, + _nested_build_airport_widgets, lengthof(_nested_build_airport_widgets) +); + +static void ShowBuildAirportPicker(Window *parent) +{ + new BuildAirportWindow(&_build_airport_desc, parent); +} + +void InitializeAirportGui() +{ + _selected_airport_class = APC_BEGIN; + _selected_airport_index = -1; +} diff --git a/src/animated_tile.cpp b/src/animated_tile.cpp new file mode 100644 index 0000000..78dda8b --- /dev/null +++ b/src/animated_tile.cpp @@ -0,0 +1,99 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file animated_tile.cpp Everything related to animated tiles. */ + +#include "stdafx.h" +#include "core/alloc_func.hpp" +#include "tile_cmd.h" +#include "viewport_func.h" + +#include "safeguards.h" + +/** The table/list with animated tiles. */ +TileIndex *_animated_tile_list = NULL; +/** The number of animated tiles in the current state. */ +uint _animated_tile_count = 0; +/** The number of slots for animated tiles allocated currently. */ +uint _animated_tile_allocated = 0; + +/** + * Removes the given tile from the animated tile table. + * @param tile the tile to remove + */ +void DeleteAnimatedTile(TileIndex tile) +{ + for (TileIndex *ti = _animated_tile_list; ti < _animated_tile_list + _animated_tile_count; ti++) { + if (tile == *ti) { + /* Remove the hole + * The order of the remaining elements must stay the same, otherwise the animation loop + * may miss a tile; that's why we must use memmove instead of just moving the last element. + */ + memmove(ti, ti + 1, (_animated_tile_list + _animated_tile_count - (ti + 1)) * sizeof(*ti)); + _animated_tile_count--; + MarkTileDirtyByTile(tile); + return; + } + } +} + +/** + * Add the given tile to the animated tile table (if it does not exist + * on that table yet). Also increases the size of the table if necessary. + * @param tile the tile to make animated + */ +void AddAnimatedTile(TileIndex tile) +{ + MarkTileDirtyByTile(tile); + + for (const TileIndex *ti = _animated_tile_list; ti < _animated_tile_list + _animated_tile_count; ti++) { + if (tile == *ti) return; + } + + /* Table not large enough, so make it larger */ + if (_animated_tile_count == _animated_tile_allocated) { + _animated_tile_allocated *= 2; + _animated_tile_list = ReallocT(_animated_tile_list, _animated_tile_allocated); + } + + _animated_tile_list[_animated_tile_count] = tile; + _animated_tile_count++; +} + +/** + * Animate all tiles in the animated tile list, i.e.\ call AnimateTile on them. + */ +void AnimateAnimatedTiles() +{ + const TileIndex *ti = _animated_tile_list; + while (ti < _animated_tile_list + _animated_tile_count) { + const TileIndex curr = *ti; + AnimateTile(curr); + /* During the AnimateTile call, DeleteAnimatedTile could have been called, + * deleting an element we've already processed and pushing the rest one + * slot to the left. We can detect this by checking whether the index + * in the current slot has changed - if it has, an element has been deleted, + * and we should process the current slot again instead of going forward. + * NOTE: this will still break if more than one animated tile is being + * deleted during the same AnimateTile call, but no code seems to + * be doing this anyway. + */ + if (*ti == curr) ++ti; + } +} + +/** + * Initialize all animated tile variables to some known begin point + */ +void InitializeAnimatedTiles() +{ + _animated_tile_list = ReallocT(_animated_tile_list, 256); + _animated_tile_count = 0; + _animated_tile_allocated = 256; +} diff --git a/src/animated_tile_func.h b/src/animated_tile_func.h new file mode 100644 index 0000000..9634ecd --- /dev/null +++ b/src/animated_tile_func.h @@ -0,0 +1,22 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file animated_tile_func.h %Tile animation! */ + +#ifndef ANIMATED_TILE_FUNC_H +#define ANIMATED_TILE_FUNC_H + +#include "tile_type.h" + +void AddAnimatedTile(TileIndex tile); +void DeleteAnimatedTile(TileIndex tile); +void AnimateAnimatedTiles(); +void InitializeAnimatedTiles(); + +#endif /* ANIMATED_TILE_FUNC_H */ diff --git a/src/articulated_vehicles.cpp b/src/articulated_vehicles.cpp new file mode 100644 index 0000000..193c5ac --- /dev/null +++ b/src/articulated_vehicles.cpp @@ -0,0 +1,450 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file articulated_vehicles.cpp Implementation of articulated vehicles. */ + +#include "stdafx.h" +#include "train.h" +#include "roadveh.h" +#include "vehicle_func.h" +#include "engine_func.h" +#include "company_func.h" +#include "newgrf.h" + +#include "table/strings.h" + +#include "safeguards.h" + +static const uint MAX_ARTICULATED_PARTS = 100; ///< Maximum of articulated parts per vehicle, i.e. when to abort calling the articulated vehicle callback. + +/** + * Determines the next articulated part to attach + * @param index Position in chain + * @param front_type Front engine type + * @param front Front engine + * @param mirrored Returns whether the part shall be flipped. + * @return engine to add or INVALID_ENGINE + */ +static EngineID GetNextArticulatedPart(uint index, EngineID front_type, Vehicle *front = NULL, bool *mirrored = NULL) +{ + assert(front == NULL || front->engine_type == front_type); + + const Engine *front_engine = Engine::Get(front_type); + + uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, index, 0, front_type, front); + if (callback == CALLBACK_FAILED) return INVALID_ENGINE; + + if (front_engine->GetGRF()->grf_version < 8) { + /* 8 bits, bit 7 for mirroring */ + callback = GB(callback, 0, 8); + if (callback == 0xFF) return INVALID_ENGINE; + if (mirrored != NULL) *mirrored = HasBit(callback, 7); + callback = GB(callback, 0, 7); + } else { + /* 15 bits, bit 14 for mirroring */ + if (callback == 0x7FFF) return INVALID_ENGINE; + if (mirrored != NULL) *mirrored = HasBit(callback, 14); + callback = GB(callback, 0, 14); + } + + return GetNewEngineID(front_engine->GetGRF(), front_engine->type, callback); +} + +/** + * Does a NewGRF report that this should be an articulated vehicle? + * @param engine_type The engine to check. + * @return True iff the articulated engine callback flag is set. + */ +bool IsArticulatedEngine(EngineID engine_type) +{ + return HasBit(EngInfo(engine_type)->callback_mask, CBM_VEHICLE_ARTIC_ENGINE); +} + +/** + * Count the number of articulated parts of an engine. + * @param engine_type The engine to get the number of parts of. + * @param purchase_window Whether we are in the scope of the purchase window or not, i.e. whether we cannot allocate vehicles. + * @return The number of parts. + */ +uint CountArticulatedParts(EngineID engine_type, bool purchase_window) +{ + if (!HasBit(EngInfo(engine_type)->callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return 0; + + /* If we can't allocate a vehicle now, we can't allocate it in the command + * either, so it doesn't matter how many articulated parts there are. */ + if (!Vehicle::CanAllocateItem()) return 0; + + Vehicle *v = NULL; + if (!purchase_window) { + v = new Vehicle(); + v->engine_type = engine_type; + v->owner = _current_company; + } + + uint i; + for (i = 1; i < MAX_ARTICULATED_PARTS; i++) { + if (GetNextArticulatedPart(i, engine_type, v) == INVALID_ENGINE) break; + } + + delete v; + + return i - 1; +} + + +/** + * Returns the default (non-refitted) capacity of a specific EngineID. + * @param engine the EngineID of interest + * @param cargo_type returns the default cargo type, if needed + * @return capacity + */ +static inline uint16 GetVehicleDefaultCapacity(EngineID engine, CargoID *cargo_type) +{ + const Engine *e = Engine::Get(engine); + CargoID cargo = (e->CanCarryCargo() ? e->GetDefaultCargoType() : (CargoID)CT_INVALID); + if (cargo_type != NULL) *cargo_type = cargo; + if (cargo == CT_INVALID) return 0; + return e->GetDisplayDefaultCapacity(); +} + +/** + * Returns all cargoes a vehicle can carry. + * @param engine the EngineID of interest + * @param include_initial_cargo_type if true the default cargo type of the vehicle is included; if false only the refit_mask + * @return bit set of CargoIDs + */ +static inline uint32 GetAvailableVehicleCargoTypes(EngineID engine, bool include_initial_cargo_type) +{ + const Engine *e = Engine::Get(engine); + if (!e->CanCarryCargo()) return 0; + + uint32 cargoes = e->info.refit_mask; + + if (include_initial_cargo_type) { + SetBit(cargoes, e->GetDefaultCargoType()); + } + + return cargoes; +} + +/** + * Get the capacity of the parts of a given engine. + * @param engine The engine to get the capacities from. + * @return The cargo capacities. + */ +CargoArray GetCapacityOfArticulatedParts(EngineID engine) +{ + CargoArray capacity; + const Engine *e = Engine::Get(engine); + + CargoID cargo_type; + uint16 cargo_capacity = GetVehicleDefaultCapacity(engine, &cargo_type); + if (cargo_type < NUM_CARGO) capacity[cargo_type] = cargo_capacity; + + if (!e->IsGroundVehicle()) return capacity; + + if (!HasBit(e->info.callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return capacity; + + for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) { + EngineID artic_engine = GetNextArticulatedPart(i, engine); + if (artic_engine == INVALID_ENGINE) break; + + cargo_capacity = GetVehicleDefaultCapacity(artic_engine, &cargo_type); + if (cargo_type < NUM_CARGO) capacity[cargo_type] += cargo_capacity; + } + + return capacity; +} + +/** + * Get the default cargoes and refits of an articulated vehicle. + * The refits are linked to a cargo rather than an articulated part to prevent a long list of parts. + * @param engine Model to investigate. + * @param[out] cargoes Total amount of units that can be transported, summed by cargo. + * @param[out] refits Whether a (possibly partial) refit for each cargo is possible. + */ +void GetArticulatedVehicleCargoesAndRefits(EngineID engine, CargoArray *cargoes, uint32 *refits) +{ + cargoes->Clear(); + *refits = 0; + + const Engine *e = Engine::Get(engine); + + CargoID cargo_type; + uint16 cargo_capacity = GetVehicleDefaultCapacity(engine, &cargo_type); + if (cargo_type < NUM_CARGO && cargo_capacity > 0) { + (*cargoes)[cargo_type] += cargo_capacity; + if (IsEngineRefittable(engine)) SetBit(*refits, cargo_type); + } + + if (!e->IsGroundVehicle() || !HasBit(e->info.callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return; + + for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) { + EngineID artic_engine = GetNextArticulatedPart(i, engine); + if (artic_engine == INVALID_ENGINE) break; + + cargo_capacity = GetVehicleDefaultCapacity(artic_engine, &cargo_type); + if (cargo_type < NUM_CARGO && cargo_capacity > 0) { + (*cargoes)[cargo_type] += cargo_capacity; + if (IsEngineRefittable(artic_engine)) SetBit(*refits, cargo_type); + } + } +} + +/** + * Checks whether any of the articulated parts is refittable + * @param engine the first part + * @return true if refittable + */ +bool IsArticulatedVehicleRefittable(EngineID engine) +{ + if (IsEngineRefittable(engine)) return true; + + const Engine *e = Engine::Get(engine); + if (!e->IsGroundVehicle()) return false; + + if (!HasBit(e->info.callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return false; + + for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) { + EngineID artic_engine = GetNextArticulatedPart(i, engine); + if (artic_engine == INVALID_ENGINE) break; + + if (IsEngineRefittable(artic_engine)) return true; + } + + return false; +} + +/** + * Merges the refit_masks of all articulated parts. + * @param engine the first part + * @param include_initial_cargo_type if true the default cargo type of the vehicle is included; if false only the refit_mask + * @param union_mask returns bit mask of CargoIDs which are a refit option for at least one articulated part + * @param intersection_mask returns bit mask of CargoIDs which are a refit option for every articulated part (with default capacity > 0) + */ +void GetArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type, uint32 *union_mask, uint32 *intersection_mask) +{ + const Engine *e = Engine::Get(engine); + uint32 veh_cargoes = GetAvailableVehicleCargoTypes(engine, include_initial_cargo_type); + *union_mask = veh_cargoes; + *intersection_mask = (veh_cargoes != 0) ? veh_cargoes : UINT32_MAX; + + if (!e->IsGroundVehicle()) return; + if (!HasBit(e->info.callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return; + + for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) { + EngineID artic_engine = GetNextArticulatedPart(i, engine); + if (artic_engine == INVALID_ENGINE) break; + + veh_cargoes = GetAvailableVehicleCargoTypes(artic_engine, include_initial_cargo_type); + *union_mask |= veh_cargoes; + if (veh_cargoes != 0) *intersection_mask &= veh_cargoes; + } +} + +/** + * Ors the refit_masks of all articulated parts. + * @param engine the first part + * @param include_initial_cargo_type if true the default cargo type of the vehicle is included; if false only the refit_mask + * @return bit mask of CargoIDs which are a refit option for at least one articulated part + */ +uint32 GetUnionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type) +{ + uint32 union_mask, intersection_mask; + GetArticulatedRefitMasks(engine, include_initial_cargo_type, &union_mask, &intersection_mask); + return union_mask; +} + +/** + * Ands the refit_masks of all articulated parts. + * @param engine the first part + * @param include_initial_cargo_type if true the default cargo type of the vehicle is included; if false only the refit_mask + * @return bit mask of CargoIDs which are a refit option for every articulated part (with default capacity > 0) + */ +uint32 GetIntersectionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type) +{ + uint32 union_mask, intersection_mask; + GetArticulatedRefitMasks(engine, include_initial_cargo_type, &union_mask, &intersection_mask); + return intersection_mask; +} + + +/** + * Tests if all parts of an articulated vehicle are refitted to the same cargo. + * Note: Vehicles not carrying anything are ignored + * @param v the first vehicle in the chain + * @param cargo_type returns the common CargoID if needed. (CT_INVALID if no part is carrying something or they are carrying different things) + * @return true if some parts are carrying different cargoes, false if all parts are carrying the same (nothing is also the same) + */ +bool IsArticulatedVehicleCarryingDifferentCargoes(const Vehicle *v, CargoID *cargo_type) +{ + CargoID first_cargo = CT_INVALID; + + do { + if (v->cargo_type != CT_INVALID && v->GetEngine()->CanCarryCargo()) { + if (first_cargo == CT_INVALID) first_cargo = v->cargo_type; + if (first_cargo != v->cargo_type) { + if (cargo_type != NULL) *cargo_type = CT_INVALID; + return true; + } + } + + v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : NULL; + } while (v != NULL); + + if (cargo_type != NULL) *cargo_type = first_cargo; + return false; +} + +/** + * Checks whether the specs of freshly build articulated vehicles are consistent with the information specified in the purchase list. + * Only essential information is checked to leave room for magic tricks/workarounds to grfcoders. + * It checks: + * For autoreplace/-renew: + * - Default cargo type (without capacity) + * - intersection and union of refit masks. + */ +void CheckConsistencyOfArticulatedVehicle(const Vehicle *v) +{ + const Engine *engine = v->GetEngine(); + + uint32 purchase_refit_union, purchase_refit_intersection; + GetArticulatedRefitMasks(v->engine_type, true, &purchase_refit_union, &purchase_refit_intersection); + CargoArray purchase_default_capacity = GetCapacityOfArticulatedParts(v->engine_type); + + uint32 real_refit_union = 0; + uint32 real_refit_intersection = UINT_MAX; + CargoArray real_default_capacity; + + do { + uint32 refit_mask = GetAvailableVehicleCargoTypes(v->engine_type, true); + real_refit_union |= refit_mask; + if (refit_mask != 0) real_refit_intersection &= refit_mask; + + assert(v->cargo_type < NUM_CARGO); + real_default_capacity[v->cargo_type] += v->cargo_cap; + + v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : NULL; + } while (v != NULL); + + /* Check whether the vehicle carries more cargoes than expected */ + bool carries_more = false; + for (CargoID cid = 0; cid < NUM_CARGO; cid++) { + if (real_default_capacity[cid] != 0 && purchase_default_capacity[cid] == 0) { + carries_more = true; + break; + } + } + + /* show a warning once for each GRF after each game load */ + if (real_refit_union != purchase_refit_union || real_refit_intersection != purchase_refit_intersection || carries_more) { + ShowNewGrfVehicleError(engine->index, STR_NEWGRF_BUGGY, STR_NEWGRF_BUGGY_ARTICULATED_CARGO, GBUG_VEH_REFIT, false); + } +} + +/** + * Add the remaining articulated parts to the given vehicle. + * @param first The head of the articulated bit. + */ +void AddArticulatedParts(Vehicle *first) +{ + VehicleType type = first->type; + if (!HasBit(EngInfo(first->engine_type)->callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return; + + Vehicle *v = first; + for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) { + bool flip_image; + EngineID engine_type = GetNextArticulatedPart(i, first->engine_type, first, &flip_image); + if (engine_type == INVALID_ENGINE) return; + + /* In the (very rare) case the GRF reported wrong number of articulated parts + * and we run out of available vehicles, bail out. */ + if (!Vehicle::CanAllocateItem()) return; + + GroundVehicleCache *gcache = v->GetGroundVehicleCache(); + gcache->first_engine = v->engine_type; // Needs to be set before first callback + + const Engine *e_artic = Engine::Get(engine_type); + switch (type) { + default: NOT_REACHED(); + + case VEH_TRAIN: { + Train *front = Train::From(first); + Train *t = new Train(); + v->SetNext(t); + v = t; + + t->subtype = 0; + t->track = front->track; + t->railtype = front->railtype; + + t->spritenum = e_artic->u.rail.image_index; + if (e_artic->CanCarryCargo()) { + t->cargo_type = e_artic->GetDefaultCargoType(); + t->cargo_cap = e_artic->u.rail.capacity; // Callback 36 is called when the consist is finished + } else { + t->cargo_type = front->cargo_type; // Needed for livery selection + t->cargo_cap = 0; + } + t->refit_cap = 0; + + t->SetArticulatedPart(); + break; + } + + case VEH_ROAD: { + RoadVehicle *front = RoadVehicle::From(first); + RoadVehicle *rv = new RoadVehicle(); + v->SetNext(rv); + v = rv; + + rv->subtype = 0; + gcache->cached_veh_length = VEHICLE_LENGTH; // Callback is called when the consist is finished + rv->state = RVSB_IN_DEPOT; + + rv->roadtype = front->roadtype; + rv->compatible_roadtypes = front->compatible_roadtypes; + + rv->spritenum = e_artic->u.road.image_index; + if (e_artic->CanCarryCargo()) { + rv->cargo_type = e_artic->GetDefaultCargoType(); + rv->cargo_cap = e_artic->u.road.capacity; // Callback 36 is called when the consist is finished + } else { + rv->cargo_type = front->cargo_type; // Needed for livery selection + rv->cargo_cap = 0; + } + rv->refit_cap = 0; + + rv->SetArticulatedPart(); + break; + } + } + + /* get common values from first engine */ + v->direction = first->direction; + v->owner = first->owner; + v->tile = first->tile; + v->x_pos = first->x_pos; + v->y_pos = first->y_pos; + v->z_pos = first->z_pos; + v->build_year = first->build_year; + v->vehstatus = first->vehstatus & ~VS_STOPPED; + + v->cargo_subtype = 0; + v->max_age = 0; + v->engine_type = engine_type; + v->value = 0; + v->cur_image = SPR_IMG_QUERY; + v->random_bits = VehicleRandomBits(); + + if (flip_image) v->spritenum++; + + v->UpdatePosition(); + } +} diff --git a/src/articulated_vehicles.h b/src/articulated_vehicles.h new file mode 100644 index 0000000..46b4da3 --- /dev/null +++ b/src/articulated_vehicles.h @@ -0,0 +1,30 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file articulated_vehicles.h Functions related to articulated vehicles. */ + +#ifndef ARTICULATED_VEHICLES_H +#define ARTICULATED_VEHICLES_H + +#include "vehicle_type.h" +#include "engine_type.h" + +uint CountArticulatedParts(EngineID engine_type, bool purchase_window); +CargoArray GetCapacityOfArticulatedParts(EngineID engine); +void AddArticulatedParts(Vehicle *first); +void GetArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type, uint32 *union_mask, uint32 *intersection_mask); +uint32 GetUnionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type); +uint32 GetIntersectionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type); +bool IsArticulatedVehicleCarryingDifferentCargoes(const Vehicle *v, CargoID *cargo_type); +bool IsArticulatedVehicleRefittable(EngineID engine); +bool IsArticulatedEngine(EngineID engine_type); +void CheckConsistencyOfArticulatedVehicle(const Vehicle *v); + + +#endif /* ARTICULATED_VEHICLES_H */ diff --git a/src/autoreplace.cpp b/src/autoreplace.cpp new file mode 100644 index 0000000..3b7f739 --- /dev/null +++ b/src/autoreplace.cpp @@ -0,0 +1,146 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file autoreplace.cpp Management of replacement lists. */ + +#include "stdafx.h" +#include "command_func.h" +#include "group.h" +#include "autoreplace_base.h" +#include "core/pool_func.hpp" + +#include "safeguards.h" + +/** The pool of autoreplace "orders". */ +EngineRenewPool _enginerenew_pool("EngineRenew"); +INSTANTIATE_POOL_METHODS(EngineRenew) + +/** + * Retrieves the EngineRenew that specifies the replacement of the given + * engine type from the given renewlist + */ +static EngineRenew *GetEngineReplacement(EngineRenewList erl, EngineID engine, GroupID group) +{ + EngineRenew *er = (EngineRenew *)erl; + + while (er != NULL) { + if (er->from == engine && GroupIsInGroup(group, er->group_id)) return er; + er = er->next; + } + return NULL; +} + +/** + * Remove all engine replacement settings for the company. + * @param erl The renewlist for a given company. + * @return The new renewlist for the company. + */ +void RemoveAllEngineReplacement(EngineRenewList *erl) +{ + EngineRenew *er = (EngineRenew *)(*erl); + EngineRenew *next; + + while (er != NULL) { + next = er->next; + delete er; + er = next; + } + *erl = NULL; // Empty list +} + +/** + * Retrieve the engine replacement in a given renewlist for an original engine type. + * @param erl The renewlist to search in. + * @param engine Engine type to be replaced. + * @param group The group related to this replacement. + * @param[out] replace_when_old Set to true if the replacement should be done when old. + * @return The engine type to replace with, or INVALID_ENGINE if no + * replacement is in the list. + */ +EngineID EngineReplacement(EngineRenewList erl, EngineID engine, GroupID group, bool *replace_when_old) +{ + const EngineRenew *er = GetEngineReplacement(erl, engine, group); + if (er == NULL && (group == DEFAULT_GROUP || (Group::IsValidID(group) && !Group::Get(group)->replace_protection))) { + /* We didn't find anything useful in the vehicle's own group so we will try ALL_GROUP */ + er = GetEngineReplacement(erl, engine, ALL_GROUP); + } + if (replace_when_old != NULL) *replace_when_old = er == NULL ? false : er->replace_when_old; + return er == NULL ? INVALID_ENGINE : er->to; +} + +/** + * Add an engine replacement to the given renewlist. + * @param erl The renewlist to add to. + * @param old_engine The original engine type. + * @param new_engine The replacement engine type. + * @param group The group related to this replacement. + * @param replace_when_old Replace when old or always? + * @param flags The calling command flags. + * @return 0 on success, CMD_ERROR on failure. + */ +CommandCost AddEngineReplacement(EngineRenewList *erl, EngineID old_engine, EngineID new_engine, GroupID group, bool replace_when_old, DoCommandFlag flags) +{ + /* Check if the old vehicle is already in the list */ + EngineRenew *er = GetEngineReplacement(*erl, old_engine, group); + if (er != NULL) { + if (flags & DC_EXEC) { + er->to = new_engine; + er->replace_when_old = replace_when_old; + } + return CommandCost(); + } + + if (!EngineRenew::CanAllocateItem()) return CMD_ERROR; + + if (flags & DC_EXEC) { + er = new EngineRenew(old_engine, new_engine); + er->group_id = group; + er->replace_when_old = replace_when_old; + + /* Insert before the first element */ + er->next = (EngineRenew *)(*erl); + *erl = (EngineRenewList)er; + } + + return CommandCost(); +} + +/** + * Remove an engine replacement from a given renewlist. + * @param erl The renewlist from which to remove the replacement + * @param engine The original engine type. + * @param group The group related to this replacement. + * @param flags The calling command flags. + * @return 0 on success, CMD_ERROR on failure. + */ +CommandCost RemoveEngineReplacement(EngineRenewList *erl, EngineID engine, GroupID group, DoCommandFlag flags) +{ + EngineRenew *er = (EngineRenew *)(*erl); + EngineRenew *prev = NULL; + + while (er != NULL) { + if (er->from == engine && er->group_id == group) { + if (flags & DC_EXEC) { + if (prev == NULL) { // First element + /* The second becomes the new first element */ + *erl = (EngineRenewList)er->next; + } else { + /* Cut this element out */ + prev->next = er->next; + } + delete er; + } + return CommandCost(); + } + prev = er; + er = er->next; + } + + return CMD_ERROR; +} diff --git a/src/autoreplace_base.h b/src/autoreplace_base.h new file mode 100644 index 0000000..5d26586 --- /dev/null +++ b/src/autoreplace_base.h @@ -0,0 +1,49 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file autoreplace_base.h Base class for autoreplaces/autorenews. */ + +#ifndef AUTOREPLACE_BASE_H +#define AUTOREPLACE_BASE_H + +#include "core/pool_type.hpp" +#include "autoreplace_type.h" +#include "engine_type.h" +#include "group_type.h" + +typedef uint16 EngineRenewID; + +/** + * Memory pool for engine renew elements. DO NOT USE outside of engine.c. Is + * placed here so the only exception to this rule, the saveload code, can use + * it. + */ +typedef Pool EngineRenewPool; +extern EngineRenewPool _enginerenew_pool; + +/** + * Struct to store engine replacements. DO NOT USE outside of engine.c. Is + * placed here so the only exception to this rule, the saveload code, can use + * it. + */ +struct EngineRenew : EngineRenewPool::PoolItem<&_enginerenew_pool> { + EngineID from; + EngineID to; + EngineRenew *next; + GroupID group_id; + bool replace_when_old; ///< Do replacement only when vehicle is old. + + EngineRenew(EngineID from = INVALID_ENGINE, EngineID to = INVALID_ENGINE) : from(from), to(to) {} + ~EngineRenew() {} +}; + +#define FOR_ALL_ENGINE_RENEWS_FROM(var, start) FOR_ALL_ITEMS_FROM(EngineRenew, enginerenew_index, var, start) +#define FOR_ALL_ENGINE_RENEWS(var) FOR_ALL_ENGINE_RENEWS_FROM(var, 0) + +#endif /* AUTOREPLACE_BASE_H */ diff --git a/src/autoreplace_cmd.cpp b/src/autoreplace_cmd.cpp new file mode 100644 index 0000000..e69ac66 --- /dev/null +++ b/src/autoreplace_cmd.cpp @@ -0,0 +1,787 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file autoreplace_cmd.cpp Deals with autoreplace execution but not the setup */ + +#include "stdafx.h" +#include "company_func.h" +#include "train.h" +#include "command_func.h" +#include "engine_func.h" +#include "vehicle_func.h" +#include "autoreplace_func.h" +#include "autoreplace_gui.h" +#include "articulated_vehicles.h" +#include "core/random_func.hpp" + +#include "table/strings.h" + +#include "safeguards.h" + +extern void ChangeVehicleViewports(VehicleID from_index, VehicleID to_index); +extern void ChangeVehicleNews(VehicleID from_index, VehicleID to_index); +extern void ChangeVehicleViewWindow(VehicleID from_index, VehicleID to_index); + +/** + * Figure out if two engines got at least one type of cargo in common (refitting if needed) + * @param engine_a one of the EngineIDs + * @param engine_b the other EngineID + * @param type the type of the engines + * @return true if they can both carry the same type of cargo (or at least one of them got no capacity at all) + */ +static bool EnginesHaveCargoInCommon(EngineID engine_a, EngineID engine_b) +{ + uint32 available_cargoes_a = GetUnionOfArticulatedRefitMasks(engine_a, true); + uint32 available_cargoes_b = GetUnionOfArticulatedRefitMasks(engine_b, true); + return (available_cargoes_a == 0 || available_cargoes_b == 0 || (available_cargoes_a & available_cargoes_b) != 0); +} + +/** + * Checks some basic properties whether autoreplace is allowed + * @param from Origin engine + * @param to Destination engine + * @param company Company to check for + * @return true if autoreplace is allowed + */ +bool CheckAutoreplaceValidity(EngineID from, EngineID to, CompanyID company) +{ + assert(Engine::IsValidID(from) && Engine::IsValidID(to)); + + /* we can't replace an engine into itself (that would be autorenew) */ + if (from == to) return false; + + const Engine *e_from = Engine::Get(from); + const Engine *e_to = Engine::Get(to); + VehicleType type = e_from->type; + + /* check that the new vehicle type is available to the company and its type is the same as the original one */ + if (!IsEngineBuildable(to, type, company)) return false; + + switch (type) { + case VEH_TRAIN: { + /* make sure the railtypes are compatible */ + if ((GetRailTypeInfo(e_from->u.rail.railtype)->compatible_railtypes & GetRailTypeInfo(e_to->u.rail.railtype)->compatible_railtypes) == 0) return false; + + /* make sure we do not replace wagons with engines or vice versa */ + if ((e_from->u.rail.railveh_type == RAILVEH_WAGON) != (e_to->u.rail.railveh_type == RAILVEH_WAGON)) return false; + break; + } + + case VEH_ROAD: + /* make sure that we do not replace a tram with a normal road vehicles or vice versa */ + if (HasBit(e_from->info.misc_flags, EF_ROAD_TRAM) != HasBit(e_to->info.misc_flags, EF_ROAD_TRAM)) return false; + break; + + case VEH_AIRCRAFT: + /* make sure that we do not replace a plane with a helicopter or vice versa */ + if ((e_from->u.air.subtype & AIR_CTOL) != (e_to->u.air.subtype & AIR_CTOL)) return false; + break; + + default: break; + } + + /* the engines needs to be able to carry the same cargo */ + return EnginesHaveCargoInCommon(from, to); +} + +/** + * Check the capacity of all vehicles in a chain and spread cargo if needed. + * @param v The vehicle to check. + * @pre You can only do this if the consist is not loading or unloading. It + * must not carry reserved cargo, nor cargo to be unloaded or transferred. + */ +void CheckCargoCapacity(Vehicle *v) +{ + assert(v == NULL || v->First() == v); + + for (Vehicle *src = v; src != NULL; src = src->Next()) { + assert(src->cargo.TotalCount() == src->cargo.ActionCount(VehicleCargoList::MTA_KEEP)); + + /* Do we need to more cargo away? */ + if (src->cargo.TotalCount() <= src->cargo_cap) continue; + + /* We need to move a particular amount. Try that on the other vehicles. */ + uint to_spread = src->cargo.TotalCount() - src->cargo_cap; + for (Vehicle *dest = v; dest != NULL && to_spread != 0; dest = dest->Next()) { + assert(dest->cargo.TotalCount() == dest->cargo.ActionCount(VehicleCargoList::MTA_KEEP)); + if (dest->cargo.TotalCount() >= dest->cargo_cap || dest->cargo_type != src->cargo_type) continue; + + uint amount = min(to_spread, dest->cargo_cap - dest->cargo.TotalCount()); + src->cargo.Shift(amount, &dest->cargo); + to_spread -= amount; + } + + /* Any left-overs will be thrown away, but not their feeder share. */ + if (src->cargo_cap < src->cargo.TotalCount()) src->cargo.Truncate(src->cargo.TotalCount() - src->cargo_cap); + } +} + +/** + * Transfer cargo from a single (articulated )old vehicle to the new vehicle chain + * @param old_veh Old vehicle that will be sold + * @param new_head Head of the completely constructed new vehicle chain + * @param part_of_chain The vehicle is part of a train + * @pre You can only do this if both consists are not loading or unloading. + * They must not carry reserved cargo, nor cargo to be unloaded or + * transferred. + */ +static void TransferCargo(Vehicle *old_veh, Vehicle *new_head, bool part_of_chain) +{ + assert(!part_of_chain || new_head->IsPrimaryVehicle()); + /* Loop through source parts */ + for (Vehicle *src = old_veh; src != NULL; src = src->Next()) { + assert(src->cargo.TotalCount() == src->cargo.ActionCount(VehicleCargoList::MTA_KEEP)); + if (!part_of_chain && src->type == VEH_TRAIN && src != old_veh && src != Train::From(old_veh)->other_multiheaded_part && !src->IsArticulatedPart()) { + /* Skip vehicles, which do not belong to old_veh */ + src = src->GetLastEnginePart(); + continue; + } + if (src->cargo_type >= NUM_CARGO || src->cargo.TotalCount() == 0) continue; + + /* Find free space in the new chain */ + for (Vehicle *dest = new_head; dest != NULL && src->cargo.TotalCount() > 0; dest = dest->Next()) { + assert(dest->cargo.TotalCount() == dest->cargo.ActionCount(VehicleCargoList::MTA_KEEP)); + if (!part_of_chain && dest->type == VEH_TRAIN && dest != new_head && dest != Train::From(new_head)->other_multiheaded_part && !dest->IsArticulatedPart()) { + /* Skip vehicles, which do not belong to new_head */ + dest = dest->GetLastEnginePart(); + continue; + } + if (dest->cargo_type != src->cargo_type) continue; + + uint amount = min(src->cargo.TotalCount(), dest->cargo_cap - dest->cargo.TotalCount()); + if (amount <= 0) continue; + + src->cargo.Shift(amount, &dest->cargo); + } + } + + /* Update train weight etc., the old vehicle will be sold anyway */ + if (part_of_chain && new_head->type == VEH_TRAIN) Train::From(new_head)->ConsistChanged(CCF_LOADUNLOAD); +} + +/** + * Tests whether refit orders that applied to v will also apply to the new vehicle type + * @param v The vehicle to be replaced + * @param engine_type The type we want to replace with + * @return true iff all refit orders stay valid + */ +static bool VerifyAutoreplaceRefitForOrders(const Vehicle *v, EngineID engine_type) +{ + + uint32 union_refit_mask_a = GetUnionOfArticulatedRefitMasks(v->engine_type, false); + uint32 union_refit_mask_b = GetUnionOfArticulatedRefitMasks(engine_type, false); + + const Order *o; + const Vehicle *u = (v->type == VEH_TRAIN) ? v->First() : v; + FOR_VEHICLE_ORDERS(u, o) { + if (!o->IsRefit() || o->IsAutoRefit()) continue; + CargoID cargo_type = o->GetRefitCargo(); + + if (!HasBit(union_refit_mask_a, cargo_type)) continue; + if (!HasBit(union_refit_mask_b, cargo_type)) return false; + } + + return true; +} + +/** + * Function to find what type of cargo to refit to when autoreplacing + * @param *v Original vehicle that is being replaced. + * @param engine_type The EngineID of the vehicle that is being replaced to + * @param part_of_chain The vehicle is part of a train + * @return The cargo type to replace to + * CT_NO_REFIT is returned if no refit is needed + * CT_INVALID is returned when both old and new vehicle got cargo capacity and refitting the new one to the old one's cargo type isn't possible + */ +static CargoID GetNewCargoTypeForReplace(Vehicle *v, EngineID engine_type, bool part_of_chain) +{ + uint32 available_cargo_types, union_mask; + GetArticulatedRefitMasks(engine_type, true, &union_mask, &available_cargo_types); + + if (union_mask == 0) return CT_NO_REFIT; // Don't try to refit an engine with no cargo capacity + + CargoID cargo_type; + if (IsArticulatedVehicleCarryingDifferentCargoes(v, &cargo_type)) return CT_INVALID; // We cannot refit to mixed cargoes in an automated way + + if (cargo_type == CT_INVALID) { + if (v->type != VEH_TRAIN) return CT_NO_REFIT; // If the vehicle does not carry anything at all, every replacement is fine. + + if (!part_of_chain) return CT_NO_REFIT; + + /* the old engine didn't have cargo capacity, but the new one does + * now we will figure out what cargo the train is carrying and refit to fit this */ + + for (v = v->First(); v != NULL; v = v->Next()) { + if (!v->GetEngine()->CanCarryCargo()) continue; + /* Now we found a cargo type being carried on the train and we will see if it is possible to carry to this one */ + if (HasBit(available_cargo_types, v->cargo_type)) return v->cargo_type; + } + + return CT_NO_REFIT; // We failed to find a cargo type on the old vehicle and we will not refit the new one + } else { + if (!HasBit(available_cargo_types, cargo_type)) return CT_INVALID; // We can't refit the vehicle to carry the cargo we want + + if (part_of_chain && !VerifyAutoreplaceRefitForOrders(v, engine_type)) return CT_INVALID; // Some refit orders lose their effect + + return cargo_type; + } +} + +/** + * Get the EngineID of the replacement for a vehicle + * @param v The vehicle to find a replacement for + * @param c The vehicle's owner (it's faster to forward the pointer than refinding it) + * @param always_replace Always replace, even if not old. + * @param [out] e the EngineID of the replacement. INVALID_ENGINE if no replacement is found + * @return Error if the engine to build is not available + */ +static CommandCost GetNewEngineType(const Vehicle *v, const Company *c, bool always_replace, EngineID &e) +{ + assert(v->type != VEH_TRAIN || !v->IsArticulatedPart()); + + e = INVALID_ENGINE; + + if (v->type == VEH_TRAIN && Train::From(v)->IsRearDualheaded()) { + /* we build the rear ends of multiheaded trains with the front ones */ + return CommandCost(); + } + + bool replace_when_old; + e = EngineReplacementForCompany(c, v->engine_type, v->group_id, &replace_when_old); + if (!always_replace && replace_when_old && !v->NeedsAutorenewing(c, false)) e = INVALID_ENGINE; + + /* Autoreplace, if engine is available */ + if (e != INVALID_ENGINE && IsEngineBuildable(e, v->type, _current_company)) { + return CommandCost(); + } + + /* Autorenew if needed */ + if (v->NeedsAutorenewing(c)) e = v->engine_type; + + /* Nothing to do or all is fine? */ + if (e == INVALID_ENGINE || IsEngineBuildable(e, v->type, _current_company)) return CommandCost(); + + /* The engine we need is not available. Report error to user */ + return CommandCost(STR_ERROR_RAIL_VEHICLE_NOT_AVAILABLE + v->type); +} + +/** + * Builds and refits a replacement vehicle + * Important: The old vehicle is still in the original vehicle chain (used for determining the cargo when the old vehicle did not carry anything, but the new one does) + * @param old_veh A single (articulated/multiheaded) vehicle that shall be replaced. + * @param new_vehicle Returns the newly build and refitted vehicle + * @param part_of_chain The vehicle is part of a train + * @return cost or error + */ +static CommandCost BuildReplacementVehicle(Vehicle *old_veh, Vehicle **new_vehicle, bool part_of_chain) +{ + *new_vehicle = NULL; + + /* Shall the vehicle be replaced? */ + const Company *c = Company::Get(_current_company); + EngineID e; + CommandCost cost = GetNewEngineType(old_veh, c, true, e); + if (cost.Failed()) return cost; + if (e == INVALID_ENGINE) return CommandCost(); // neither autoreplace is set, nor autorenew is triggered + + /* Does it need to be refitted */ + CargoID refit_cargo = GetNewCargoTypeForReplace(old_veh, e, part_of_chain); + if (refit_cargo == CT_INVALID) return CommandCost(); // incompatible cargoes + + /* Build the new vehicle */ + cost = DoCommand(old_veh->tile, e, 0, DC_EXEC | DC_AUTOREPLACE, GetCmdBuildVeh(old_veh)); + if (cost.Failed()) return cost; + + Vehicle *new_veh = Vehicle::Get(_new_vehicle_id); + *new_vehicle = new_veh; + + /* Refit the vehicle if needed */ + if (refit_cargo != CT_NO_REFIT) { + byte subtype = GetBestFittingSubType(old_veh, new_veh, refit_cargo); + + cost.AddCost(DoCommand(0, new_veh->index, refit_cargo | (subtype << 8), DC_EXEC, GetCmdRefitVeh(new_veh))); + assert(cost.Succeeded()); // This should be ensured by GetNewCargoTypeForReplace() + } + + /* Try to reverse the vehicle, but do not care if it fails as the new type might not be reversible */ + if (new_veh->type == VEH_TRAIN && HasBit(Train::From(old_veh)->flags, VRF_REVERSE_DIRECTION)) { + DoCommand(0, new_veh->index, true, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION); + } + + return cost; +} + +/** + * Issue a start/stop command + * @param v a vehicle + * @param evaluate_callback shall the start/stop callback be evaluated? + * @return success or error + */ +static inline CommandCost CmdStartStopVehicle(const Vehicle *v, bool evaluate_callback) +{ + return DoCommand(0, v->index, evaluate_callback ? 1 : 0, DC_EXEC | DC_AUTOREPLACE, CMD_START_STOP_VEHICLE); +} + +/** + * Issue a train vehicle move command + * @param v The vehicle to move + * @param after The vehicle to insert 'v' after, or NULL to start new chain + * @param flags the command flags to use + * @param whole_chain move all vehicles following 'v' (true), or only 'v' (false) + * @return success or error + */ +static inline CommandCost CmdMoveVehicle(const Vehicle *v, const Vehicle *after, DoCommandFlag flags, bool whole_chain) +{ + return DoCommand(0, v->index | (whole_chain ? 1 : 0) << 20, after != NULL ? after->index : INVALID_VEHICLE, flags | DC_NO_CARGO_CAP_CHECK, CMD_MOVE_RAIL_VEHICLE); +} + +/** + * Copy head specific things to the new vehicle chain after it was successfully constructed + * @param old_head The old front vehicle (no wagons attached anymore) + * @param new_head The new head of the completely replaced vehicle chain + * @param flags the command flags to use + */ +static CommandCost CopyHeadSpecificThings(Vehicle *old_head, Vehicle *new_head, DoCommandFlag flags) +{ + CommandCost cost = CommandCost(); + + /* Share orders */ + if (cost.Succeeded() && old_head != new_head) cost.AddCost(DoCommand(0, new_head->index | CO_SHARE << 30, old_head->index, DC_EXEC, CMD_CLONE_ORDER)); + + /* Copy group membership */ + if (cost.Succeeded() && old_head != new_head) cost.AddCost(DoCommand(0, old_head->group_id, new_head->index, DC_EXEC, CMD_ADD_VEHICLE_GROUP)); + + /* Perform start/stop check whether the new vehicle suits newgrf restrictions etc. */ + if (cost.Succeeded()) { + /* Start the vehicle, might be denied by certain things */ + assert((new_head->vehstatus & VS_STOPPED) != 0); + cost.AddCost(CmdStartStopVehicle(new_head, true)); + + /* Stop the vehicle again, but do not care about evil newgrfs allowing starting but not stopping :p */ + if (cost.Succeeded()) cost.AddCost(CmdStartStopVehicle(new_head, false)); + } + + /* Last do those things which do never fail (resp. we do not care about), but which are not undo-able */ + if (cost.Succeeded() && old_head != new_head && (flags & DC_EXEC) != 0) { + /* Copy other things which cannot be copied by a command and which shall not stay resetted from the build vehicle command */ + new_head->CopyVehicleConfigAndStatistics(old_head); + + /* Switch vehicle windows/news to the new vehicle, so they are not closed/deleted when the old vehicle is sold */ + ChangeVehicleViewports(old_head->index, new_head->index); + ChangeVehicleViewWindow(old_head->index, new_head->index); + ChangeVehicleNews(old_head->index, new_head->index); + } + + return cost; +} + +/** + * Replace a single unit in a free wagon chain + * @param single_unit vehicle to let autoreplace/renew operator on + * @param flags command flags + * @param nothing_to_do is set to 'false' when something was done (only valid when not failed) + * @return cost or error + */ +static CommandCost ReplaceFreeUnit(Vehicle **single_unit, DoCommandFlag flags, bool *nothing_to_do) +{ + Train *old_v = Train::From(*single_unit); + assert(!old_v->IsArticulatedPart() && !old_v->IsRearDualheaded()); + + CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, 0); + + /* Build and refit replacement vehicle */ + Vehicle *new_v = NULL; + cost.AddCost(BuildReplacementVehicle(old_v, &new_v, false)); + + /* Was a new vehicle constructed? */ + if (cost.Succeeded() && new_v != NULL) { + *nothing_to_do = false; + + if ((flags & DC_EXEC) != 0) { + /* Move the new vehicle behind the old */ + CmdMoveVehicle(new_v, old_v, DC_EXEC, false); + + /* Take over cargo + * Note: We do only transfer cargo from the old to the new vehicle. + * I.e. we do not transfer remaining cargo to other vehicles. + * Else you would also need to consider moving cargo to other free chains, + * or doing the same in ReplaceChain(), which would be quite troublesome. + */ + TransferCargo(old_v, new_v, false); + + *single_unit = new_v; + } + + /* Sell the old vehicle */ + cost.AddCost(DoCommand(0, old_v->index, 0, flags, GetCmdSellVeh(old_v))); + + /* If we are not in DC_EXEC undo everything */ + if ((flags & DC_EXEC) == 0) { + DoCommand(0, new_v->index, 0, DC_EXEC, GetCmdSellVeh(new_v)); + } + } + + return cost; +} + +/** + * Replace a whole vehicle chain + * @param chain vehicle chain to let autoreplace/renew operator on + * @param flags command flags + * @param wagon_removal remove wagons when the resulting chain occupies more tiles than the old did + * @param nothing_to_do is set to 'false' when something was done (only valid when not failed) + * @return cost or error + */ +static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon_removal, bool *nothing_to_do) +{ + Vehicle *old_head = *chain; + assert(old_head->IsPrimaryVehicle()); + + CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, 0); + + if (old_head->type == VEH_TRAIN) { + /* Store the length of the old vehicle chain, rounded up to whole tiles */ + uint16 old_total_length = CeilDiv(Train::From(old_head)->gcache.cached_total_length, TILE_SIZE) * TILE_SIZE; + + int num_units = 0; ///< Number of units in the chain + for (Train *w = Train::From(old_head); w != NULL; w = w->GetNextUnit()) num_units++; + + Train **old_vehs = CallocT(num_units); ///< Will store vehicles of the old chain in their order + Train **new_vehs = CallocT(num_units); ///< New vehicles corresponding to old_vehs or NULL if no replacement + Money *new_costs = MallocT(num_units); ///< Costs for buying and refitting the new vehicles + + /* Collect vehicles and build replacements + * Note: The replacement vehicles can only successfully build as long as the old vehicles are still in their chain */ + int i; + Train *w; + for (w = Train::From(old_head), i = 0; w != NULL; w = w->GetNextUnit(), i++) { + assert(i < num_units); + old_vehs[i] = w; + + CommandCost ret = BuildReplacementVehicle(old_vehs[i], (Vehicle**)&new_vehs[i], true); + cost.AddCost(ret); + if (cost.Failed()) break; + + new_costs[i] = ret.GetCost(); + if (new_vehs[i] != NULL) *nothing_to_do = false; + } + Train *new_head = (new_vehs[0] != NULL ? new_vehs[0] : old_vehs[0]); + + /* Note: When autoreplace has already failed here, old_vehs[] is not completely initialized. But it is also not needed. */ + if (cost.Succeeded()) { + /* Separate the head, so we can start constructing the new chain */ + Train *second = Train::From(old_head)->GetNextUnit(); + if (second != NULL) cost.AddCost(CmdMoveVehicle(second, NULL, DC_EXEC | DC_AUTOREPLACE, true)); + + assert(Train::From(new_head)->GetNextUnit() == NULL); + + /* Append engines to the new chain + * We do this from back to front, so that the head of the temporary vehicle chain does not change all the time. + * That way we also have less trouble when exceeding the unitnumber limit. + * OTOH the vehicle attach callback is more expensive this way :s */ + Train *last_engine = NULL; ///< Shall store the last engine unit after this step + if (cost.Succeeded()) { + for (int i = num_units - 1; i > 0; i--) { + Train *append = (new_vehs[i] != NULL ? new_vehs[i] : old_vehs[i]); + + if (RailVehInfo(append->engine_type)->railveh_type == RAILVEH_WAGON) continue; + + if (new_vehs[i] != NULL) { + /* Move the old engine to a separate row with DC_AUTOREPLACE. Else + * moving the wagon in front may fail later due to unitnumber limit. + * (We have to attach wagons without DC_AUTOREPLACE.) */ + CmdMoveVehicle(old_vehs[i], NULL, DC_EXEC | DC_AUTOREPLACE, false); + } + + if (last_engine == NULL) last_engine = append; + cost.AddCost(CmdMoveVehicle(append, new_head, DC_EXEC, false)); + if (cost.Failed()) break; + } + if (last_engine == NULL) last_engine = new_head; + } + + /* When wagon removal is enabled and the new engines without any wagons are already longer than the old, we have to fail */ + if (cost.Succeeded() && wagon_removal && new_head->gcache.cached_total_length > old_total_length) cost = CommandCost(STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT); + + /* Append/insert wagons into the new vehicle chain + * We do this from back to front, so we can stop when wagon removal or maximum train length (i.e. from mammoth-train setting) is triggered. + */ + if (cost.Succeeded()) { + for (int i = num_units - 1; i > 0; i--) { + assert(last_engine != NULL); + Vehicle *append = (new_vehs[i] != NULL ? new_vehs[i] : old_vehs[i]); + + if (RailVehInfo(append->engine_type)->railveh_type == RAILVEH_WAGON) { + /* Insert wagon after 'last_engine' */ + CommandCost res = CmdMoveVehicle(append, last_engine, DC_EXEC, false); + + /* When we allow removal of wagons, either the move failing due + * to the train becoming too long, or the train becoming longer + * would move the vehicle to the empty vehicle chain. */ + if (wagon_removal && (res.Failed() ? res.GetErrorMessage() == STR_ERROR_TRAIN_TOO_LONG : new_head->gcache.cached_total_length > old_total_length)) { + CmdMoveVehicle(append, NULL, DC_EXEC | DC_AUTOREPLACE, false); + break; + } + + cost.AddCost(res); + if (cost.Failed()) break; + } else { + /* We have reached 'last_engine', continue with the next engine towards the front */ + assert(append == last_engine); + last_engine = last_engine->GetPrevUnit(); + } + } + } + + /* Sell superfluous new vehicles that could not be inserted. */ + if (cost.Succeeded() && wagon_removal) { + assert(new_head->gcache.cached_total_length <= _settings_game.vehicle.max_train_length * TILE_SIZE); + for (int i = 1; i < num_units; i++) { + Vehicle *wagon = new_vehs[i]; + if (wagon == NULL) continue; + if (wagon->First() == new_head) break; + + assert(RailVehInfo(wagon->engine_type)->railveh_type == RAILVEH_WAGON); + + /* Sell wagon */ + CommandCost ret = DoCommand(0, wagon->index, 0, DC_EXEC, GetCmdSellVeh(wagon)); + assert(ret.Succeeded()); + new_vehs[i] = NULL; + + /* Revert the money subtraction when the vehicle was built. + * This value is different from the sell value, esp. because of refitting */ + cost.AddCost(-new_costs[i]); + } + } + + /* The new vehicle chain is constructed, now take over orders and everything... */ + if (cost.Succeeded()) cost.AddCost(CopyHeadSpecificThings(old_head, new_head, flags)); + + if (cost.Succeeded()) { + /* Success ! */ + if ((flags & DC_EXEC) != 0 && new_head != old_head) { + *chain = new_head; + } + + /* Transfer cargo of old vehicles and sell them */ + for (int i = 0; i < num_units; i++) { + Vehicle *w = old_vehs[i]; + /* Is the vehicle again part of the new chain? + * Note: We cannot test 'new_vehs[i] != NULL' as wagon removal might cause to remove both */ + if (w->First() == new_head) continue; + + if ((flags & DC_EXEC) != 0) TransferCargo(w, new_head, true); + + /* Sell the vehicle. + * Note: This might temporarly construct new trains, so use DC_AUTOREPLACE to prevent + * it from failing due to engine limits. */ + cost.AddCost(DoCommand(0, w->index, 0, flags | DC_AUTOREPLACE, GetCmdSellVeh(w))); + if ((flags & DC_EXEC) != 0) { + old_vehs[i] = NULL; + if (i == 0) old_head = NULL; + } + } + + if ((flags & DC_EXEC) != 0) CheckCargoCapacity(new_head); + } + + /* If we are not in DC_EXEC undo everything, i.e. rearrange old vehicles. + * We do this from back to front, so that the head of the temporary vehicle chain does not change all the time. + * Note: The vehicle attach callback is disabled here :) */ + if ((flags & DC_EXEC) == 0) { + /* Separate the head, so we can reattach the old vehicles */ + Train *second = Train::From(old_head)->GetNextUnit(); + if (second != NULL) CmdMoveVehicle(second, NULL, DC_EXEC | DC_AUTOREPLACE, true); + + assert(Train::From(old_head)->GetNextUnit() == NULL); + + for (int i = num_units - 1; i > 0; i--) { + CommandCost ret = CmdMoveVehicle(old_vehs[i], old_head, DC_EXEC | DC_AUTOREPLACE, false); + assert(ret.Succeeded()); + } + } + } + + /* Finally undo buying of new vehicles */ + if ((flags & DC_EXEC) == 0) { + for (int i = num_units - 1; i >= 0; i--) { + if (new_vehs[i] != NULL) { + DoCommand(0, new_vehs[i]->index, 0, DC_EXEC, GetCmdSellVeh(new_vehs[i])); + new_vehs[i] = NULL; + } + } + } + + free(old_vehs); + free(new_vehs); + free(new_costs); + } else { + /* Build and refit replacement vehicle */ + Vehicle *new_head = NULL; + cost.AddCost(BuildReplacementVehicle(old_head, &new_head, true)); + + /* Was a new vehicle constructed? */ + if (cost.Succeeded() && new_head != NULL) { + *nothing_to_do = false; + + /* The new vehicle is constructed, now take over orders and everything... */ + cost.AddCost(CopyHeadSpecificThings(old_head, new_head, flags)); + + if (cost.Succeeded()) { + /* The new vehicle is constructed, now take over cargo */ + if ((flags & DC_EXEC) != 0) { + TransferCargo(old_head, new_head, true); + *chain = new_head; + } + + /* Sell the old vehicle */ + cost.AddCost(DoCommand(0, old_head->index, 0, flags, GetCmdSellVeh(old_head))); + } + + /* If we are not in DC_EXEC undo everything */ + if ((flags & DC_EXEC) == 0) { + DoCommand(0, new_head->index, 0, DC_EXEC, GetCmdSellVeh(new_head)); + } + } + } + + return cost; +} + +/** + * Autoreplaces a vehicle + * Trains are replaced as a whole chain, free wagons in depot are replaced on their own + * @param tile not used + * @param flags type of operation + * @param p1 Index of vehicle + * @param p2 not used + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdAutoreplaceVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + Vehicle *v = Vehicle::GetIfValid(p1); + if (v == NULL) return CMD_ERROR; + + CommandCost ret = CheckOwnership(v->owner); + if (ret.Failed()) return ret; + + if (!v->IsChainInDepot()) return CMD_ERROR; + if (v->vehstatus & VS_CRASHED) return CMD_ERROR; + + bool free_wagon = false; + if (v->type == VEH_TRAIN) { + Train *t = Train::From(v); + if (t->IsArticulatedPart() || t->IsRearDualheaded()) return CMD_ERROR; + free_wagon = !t->IsFrontEngine(); + if (free_wagon && t->First()->IsFrontEngine()) return CMD_ERROR; + } else { + if (!v->IsPrimaryVehicle()) return CMD_ERROR; + } + + const Company *c = Company::Get(_current_company); + bool wagon_removal = c->settings.renew_keep_length; + + /* Test whether any replacement is set, before issuing a whole lot of commands that would end in nothing changed */ + Vehicle *w = v; + bool any_replacements = false; + while (w != NULL) { + EngineID e; + CommandCost cost = GetNewEngineType(w, c, false, e); + if (cost.Failed()) return cost; + any_replacements |= (e != INVALID_ENGINE); + w = (!free_wagon && w->type == VEH_TRAIN ? Train::From(w)->GetNextUnit() : NULL); + } + + CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, 0); + bool nothing_to_do = true; + + if (any_replacements) { + bool was_stopped = free_wagon || ((v->vehstatus & VS_STOPPED) != 0); + + /* Stop the vehicle */ + if (!was_stopped) cost.AddCost(CmdStartStopVehicle(v, true)); + if (cost.Failed()) return cost; + + assert(free_wagon || v->IsStoppedInDepot()); + + /* We have to construct the new vehicle chain to test whether it is valid. + * Vehicle construction needs random bits, so we have to save the random seeds + * to prevent desyncs and to replay newgrf callbacks during DC_EXEC */ + SavedRandomSeeds saved_seeds; + SaveRandomSeeds(&saved_seeds); + if (free_wagon) { + cost.AddCost(ReplaceFreeUnit(&v, flags & ~DC_EXEC, ¬hing_to_do)); + } else { + cost.AddCost(ReplaceChain(&v, flags & ~DC_EXEC, wagon_removal, ¬hing_to_do)); + } + RestoreRandomSeeds(saved_seeds); + + if (cost.Succeeded() && (flags & DC_EXEC) != 0) { + CommandCost ret; + if (free_wagon) { + ret = ReplaceFreeUnit(&v, flags, ¬hing_to_do); + } else { + ret = ReplaceChain(&v, flags, wagon_removal, ¬hing_to_do); + } + assert(ret.Succeeded() && ret.GetCost() == cost.GetCost()); + } + + /* Restart the vehicle */ + if (!was_stopped) cost.AddCost(CmdStartStopVehicle(v, false)); + } + + if (cost.Succeeded() && nothing_to_do) cost = CommandCost(STR_ERROR_AUTOREPLACE_NOTHING_TO_DO); + return cost; +} + +/** + * Change engine renewal parameters + * @param tile unused + * @param flags operation to perform + * @param p1 packed data + * - bit 0 = replace when engine gets old? + * - bits 16-31 = engine group + * @param p2 packed data + * - bits 0-15 = old engine type + * - bits 16-31 = new engine type + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdSetAutoReplace(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + Company *c = Company::GetIfValid(_current_company); + if (c == NULL) return CMD_ERROR; + + EngineID old_engine_type = GB(p2, 0, 16); + EngineID new_engine_type = GB(p2, 16, 16); + GroupID id_g = GB(p1, 16, 16); + CommandCost cost; + + if (Group::IsValidID(id_g) ? Group::Get(id_g)->owner != _current_company : !IsAllGroupID(id_g) && !IsDefaultGroupID(id_g)) return CMD_ERROR; + if (!Engine::IsValidID(old_engine_type)) return CMD_ERROR; + + if (new_engine_type != INVALID_ENGINE) { + if (!Engine::IsValidID(new_engine_type)) return CMD_ERROR; + if (!CheckAutoreplaceValidity(old_engine_type, new_engine_type, _current_company)) return CMD_ERROR; + + cost = AddEngineReplacementForCompany(c, old_engine_type, new_engine_type, id_g, HasBit(p1, 0), flags); + } else { + cost = RemoveEngineReplacementForCompany(c, old_engine_type, id_g, flags); + } + + if (flags & DC_EXEC) { + GroupStatistics::UpdateAutoreplace(_current_company); + if (IsLocalCompany()) SetWindowDirty(WC_REPLACE_VEHICLE, Engine::Get(old_engine_type)->type); + } + if ((flags & DC_EXEC) && IsLocalCompany()) InvalidateAutoreplaceWindow(old_engine_type, id_g); + + return cost; +} + diff --git a/src/autoreplace_func.h b/src/autoreplace_func.h new file mode 100644 index 0000000..3a6fc83 --- /dev/null +++ b/src/autoreplace_func.h @@ -0,0 +1,102 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file autoreplace_func.h Functions related to autoreplacing. */ + +#ifndef AUTOREPLACE_FUNC_H +#define AUTOREPLACE_FUNC_H + +#include "command_type.h" +#include "company_base.h" + +void RemoveAllEngineReplacement(EngineRenewList *erl); +EngineID EngineReplacement(EngineRenewList erl, EngineID engine, GroupID group, bool *replace_when_old = NULL); +CommandCost AddEngineReplacement(EngineRenewList *erl, EngineID old_engine, EngineID new_engine, GroupID group, bool replace_when_old, DoCommandFlag flags); +CommandCost RemoveEngineReplacement(EngineRenewList *erl, EngineID engine, GroupID group, DoCommandFlag flags); + +/** + * Remove all engine replacement settings for the given company. + * @param c the company. + */ +static inline void RemoveAllEngineReplacementForCompany(Company *c) +{ + RemoveAllEngineReplacement(&c->engine_renew_list); +} + +/** + * Retrieve the engine replacement for the given company and original engine type. + * @param c company. + * @param engine Engine type. + * @param group The group related to this replacement. + * @param[out] replace_when_old Set to true if the replacement should be done when old. + * @return The engine type to replace with, or INVALID_ENGINE if no + * replacement is in the list. + */ +static inline EngineID EngineReplacementForCompany(const Company *c, EngineID engine, GroupID group, bool *replace_when_old = NULL) +{ + return EngineReplacement(c->engine_renew_list, engine, group, replace_when_old); +} + +/** + * Check if a company has a replacement set up for the given engine. + * @param c Company. + * @param engine Engine type to be replaced. + * @param group The group related to this replacement. + * @return true if a replacement was set up, false otherwise. + */ +static inline bool EngineHasReplacementForCompany(const Company *c, EngineID engine, GroupID group) +{ + return EngineReplacementForCompany(c, engine, group) != INVALID_ENGINE; +} + +/** + * Check if a company has a replacement set up for the given engine when it gets old. + * @param c Company. + * @param engine Engine type to be replaced. + * @param group The group related to this replacement. + * @return True if a replacement when old was set up, false otherwise. + */ +static inline bool EngineHasReplacementWhenOldForCompany(const Company *c, EngineID engine, GroupID group) +{ + bool replace_when_old; + EngineReplacement(c->engine_renew_list, engine, group, &replace_when_old); + return replace_when_old; +} + +/** + * Add an engine replacement for the company. + * @param c Company. + * @param old_engine The original engine type. + * @param new_engine The replacement engine type. + * @param group The group related to this replacement. + * @param replace_when_old Replace when old or always? + * @param flags The calling command flags. + * @return 0 on success, CMD_ERROR on failure. + */ +static inline CommandCost AddEngineReplacementForCompany(Company *c, EngineID old_engine, EngineID new_engine, GroupID group, bool replace_when_old, DoCommandFlag flags) +{ + return AddEngineReplacement(&c->engine_renew_list, old_engine, new_engine, group, replace_when_old, flags); +} + +/** + * Remove an engine replacement for the company. + * @param c Company. + * @param engine The original engine type. + * @param group The group related to this replacement. + * @param flags The calling command flags. + * @return 0 on success, CMD_ERROR on failure. + */ +static inline CommandCost RemoveEngineReplacementForCompany(Company *c, EngineID engine, GroupID group, DoCommandFlag flags) +{ + return RemoveEngineReplacement(&c->engine_renew_list, engine, group, flags); +} + +bool CheckAutoreplaceValidity(EngineID from, EngineID to, CompanyID company); + +#endif /* AUTOREPLACE_FUNC_H */ diff --git a/src/autoreplace_gui.cpp b/src/autoreplace_gui.cpp new file mode 100644 index 0000000..691042a --- /dev/null +++ b/src/autoreplace_gui.cpp @@ -0,0 +1,722 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file autoreplace_gui.cpp GUI for autoreplace handling. */ + +#include "stdafx.h" +#include "command_func.h" +#include "vehicle_gui.h" +#include "newgrf_engine.h" +#include "rail.h" +#include "strings_func.h" +#include "window_func.h" +#include "autoreplace_func.h" +#include "company_func.h" +#include "engine_base.h" +#include "window_gui.h" +#include "engine_gui.h" +#include "settings_func.h" +#include "core/geometry_func.hpp" +#include "rail_gui.h" +#include "widgets/dropdown_func.h" + +#include "widgets/autoreplace_widget.h" + +#include "safeguards.h" + +void DrawEngineList(VehicleType type, int x, int r, int y, const GUIEngineList *eng_list, uint16 min, uint16 max, EngineID selected_id, bool show_count, GroupID selected_group); + +static int CDECL EngineNumberSorter(const EngineID *a, const EngineID *b) +{ + int r = Engine::Get(*a)->list_position - Engine::Get(*b)->list_position; + + return r; +} + +/** + * Rebuild the left autoreplace list if an engine is removed or added + * @param e Engine to check if it is removed or added + * @param id_g The group the engine belongs to + * Note: this function only works if it is called either + * - when a new vehicle is build, but before it's counted in num_engines + * - when a vehicle is deleted and after it's subtracted from num_engines + * - when not changing the count (used when changing replace orders) + */ +void InvalidateAutoreplaceWindow(EngineID e, GroupID id_g) +{ + if (GetGroupNumEngines(_local_company, id_g, e) == 0 || GetGroupNumEngines(_local_company, ALL_GROUP, e) == 0) { + /* We don't have any of this engine type. + * Either we just sold the last one, we build a new one or we stopped replacing it. + * In all cases, we need to update the left list */ + InvalidateWindowData(WC_REPLACE_VEHICLE, Engine::Get(e)->type, 1); + } +} + +/** + * When an engine is made buildable or is removed from being buildable, add/remove it from the build/autoreplace lists + * @param type The type of engine + */ +void AddRemoveEngineFromAutoreplaceAndBuildWindows(VehicleType type) +{ + InvalidateWindowData(WC_REPLACE_VEHICLE, type, 0); // Update the autoreplace window + InvalidateWindowClassesData(WC_BUILD_VEHICLE); // The build windows needs updating as well +} + +static const StringID _start_replace_dropdown[] = { + STR_REPLACE_VEHICLES_NOW, + STR_REPLACE_VEHICLES_WHEN_OLD, + INVALID_STRING_ID +}; + +/** + * Window for the autoreplacing of vehicles. + */ +class ReplaceVehicleWindow : public Window { + EngineID sel_engine[2]; ///< Selected engine left and right. + GUIEngineList engines[2]; ///< Left and right list of engines. + bool replace_engines; ///< If \c true, engines are replaced, if \c false, wagons are replaced (only for trains). + bool reset_sel_engine; ///< Also reset #sel_engine while updating left and/or right (#update_left and/or #update_right) and no valid engine selected. + GroupID sel_group; ///< Group selected to replace. + int details_height; ///< Minimal needed height of the details panels (found so far). + byte sort_criteria; ///< Criteria of sorting vehicles. + bool descending_sort_order; ///< Order of sorting vehicles. + bool show_hidden_engines; ///< Whether to show the hidden engines. + RailType sel_railtype; ///< Type of rail tracks selected. + Scrollbar *vscroll[2]; + + /** + * Figure out if an engine should be added to a list. + * @param e The EngineID. + * @param draw_left If \c true, the left list is drawn (the engines specific to the railtype you selected). + * @param show_engines If \c true, the locomotives are drawn, else the wagons are drawn (never both). + * @return \c true if the engine should be in the list (based on this check), else \c false. + */ + bool GenerateReplaceRailList(EngineID e, bool draw_left, bool show_engines) + { + const RailVehicleInfo *rvi = RailVehInfo(e); + + /* Ensure that the wagon/engine selection fits the engine. */ + if ((rvi->railveh_type == RAILVEH_WAGON) == show_engines) return false; + + if (draw_left && show_engines) { + /* Ensure that the railtype is specific to the selected one */ + if (rvi->railtype != this->sel_railtype) return false; + } + return true; + } + + + /** + * Generate an engines list + * @param draw_left true if generating the left list, otherwise false + */ + void GenerateReplaceVehList(bool draw_left) + { + EngineID selected_engine = INVALID_ENGINE; + VehicleType type = (VehicleType)this->window_number; + byte side = draw_left ? 0 : 1; + + GUIEngineList *list = &this->engines[side]; + list->Clear(); + + const Engine *e; + FOR_ALL_ENGINES_OF_TYPE(e, type) { + if (!draw_left && !this->show_hidden_engines && e->IsHidden(_local_company)) continue; + EngineID eid = e->index; + if (type == VEH_TRAIN && !this->GenerateReplaceRailList(eid, draw_left, this->replace_engines)) continue; // special rules for trains + + if (draw_left) { + const uint num_engines = GetGroupNumEngines(_local_company, this->sel_group, eid); + + /* Skip drawing the engines we don't have any of and haven't set for replacement */ + if (num_engines == 0 && EngineReplacementForCompany(Company::Get(_local_company), eid, this->sel_group) == INVALID_ENGINE) continue; + } else { + if (!CheckAutoreplaceValidity(this->sel_engine[0], eid, _local_company)) continue; + } + + *list->Append() = eid; + if (eid == this->sel_engine[side]) selected_engine = eid; // The selected engine is still in the list + } + this->sel_engine[side] = selected_engine; // update which engine we selected (the same or none, if it's not in the list anymore) + if (draw_left) { + EngList_Sort(list, &EngineNumberSorter); + } else { + _engine_sort_direction = this->descending_sort_order; + EngList_Sort(list, _engine_sort_functions[this->window_number][this->sort_criteria]); + } + } + + /** Generate the lists */ + void GenerateLists() + { + EngineID e = this->sel_engine[0]; + + if (this->engines[0].NeedRebuild()) { + /* We need to rebuild the left engines list */ + this->GenerateReplaceVehList(true); + this->vscroll[0]->SetCount(this->engines[0].Length()); + if (this->reset_sel_engine && this->sel_engine[0] == INVALID_ENGINE && this->engines[0].Length() != 0) { + this->sel_engine[0] = this->engines[0][0]; + } + } + + if (this->engines[1].NeedRebuild() || e != this->sel_engine[0]) { + /* Either we got a request to rebuild the right engines list, or the left engines list selected a different engine */ + if (this->sel_engine[0] == INVALID_ENGINE) { + /* Always empty the right engines list when nothing is selected in the left engines list */ + this->engines[1].Clear(); + this->sel_engine[1] = INVALID_ENGINE; + } else { + if (this->reset_sel_engine && this->sel_engine[0] != INVALID_ENGINE) { + /* Select the current replacement for sel_engine[0]. */ + const Company *c = Company::Get(_local_company); + this->sel_engine[1] = EngineReplacementForCompany(c, this->sel_engine[0], this->sel_group); + } + /* Regenerate the list on the right. Note: This resets sel_engine[1] to INVALID_ENGINE, if it is no longer available. */ + this->GenerateReplaceVehList(false); + this->vscroll[1]->SetCount(this->engines[1].Length()); + if (this->reset_sel_engine && this->sel_engine[1] != INVALID_ENGINE) { + int position = 0; + for (EngineID *it = this->engines[1].Begin(); it != this->engines[1].End(); ++it) { + if (*it == this->sel_engine[1]) break; + ++position; + } + this->vscroll[1]->ScrollTowards(position); + } + } + } + /* Reset the flags about needed updates */ + this->engines[0].RebuildDone(); + this->engines[1].RebuildDone(); + this->reset_sel_engine = false; + } + + /** + * Handle click on the start replace button. + * @param replace_when_old Replace now or only when old? + */ + void ReplaceClick_StartReplace(bool replace_when_old) + { + EngineID veh_from = this->sel_engine[0]; + EngineID veh_to = this->sel_engine[1]; + DoCommandP(0, (replace_when_old ? 1 : 0) | (this->sel_group << 16), veh_from + (veh_to << 16), CMD_SET_AUTOREPLACE); + } + +public: + ReplaceVehicleWindow(WindowDesc *desc, VehicleType vehicletype, GroupID id_g) : Window(desc) + { + if (vehicletype == VEH_TRAIN) { + /* For rail vehicles find the most used vehicle type, which is usually + * better than 'just' the first/previous vehicle type. */ + uint type_count[RAILTYPE_END]; + memset(type_count, 0, sizeof(type_count)); + + const Engine *e; + FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) { + if (e->u.rail.railveh_type == RAILVEH_WAGON) continue; + type_count[e->u.rail.railtype] += GetGroupNumEngines(_local_company, id_g, e->index); + } + + this->sel_railtype = RAILTYPE_BEGIN; + for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) { + if (type_count[this->sel_railtype] < type_count[rt]) this->sel_railtype = rt; + } + } + + this->replace_engines = true; // start with locomotives (all other vehicles will not read this bool) + this->engines[0].ForceRebuild(); + this->engines[1].ForceRebuild(); + this->reset_sel_engine = true; + this->details_height = ((vehicletype == VEH_TRAIN) ? 10 : 9) * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + this->sel_engine[0] = INVALID_ENGINE; + this->sel_engine[1] = INVALID_ENGINE; + this->show_hidden_engines = _engine_sort_show_hidden_engines[vehicletype]; + + this->CreateNestedTree(); + this->vscroll[0] = this->GetScrollbar(WID_RV_LEFT_SCROLLBAR); + this->vscroll[1] = this->GetScrollbar(WID_RV_RIGHT_SCROLLBAR); + + NWidgetCore *widget = this->GetWidget(WID_RV_SHOW_HIDDEN_ENGINES); + widget->widget_data = STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN + vehicletype; + widget->tool_tip = STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN_TOOLTIP + vehicletype; + widget->SetLowered(this->show_hidden_engines); + this->FinishInitNested(vehicletype); + + this->sort_criteria = _engine_sort_last_criteria[vehicletype]; + this->descending_sort_order = _engine_sort_last_order[vehicletype]; + this->owner = _local_company; + this->sel_group = id_g; + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_RV_SORT_ASCENDING_DESCENDING: { + Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); + d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better. + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + + case WID_RV_LEFT_MATRIX: + case WID_RV_RIGHT_MATRIX: + resize->height = GetEngineListHeight((VehicleType)this->window_number); + size->height = (this->window_number <= VEH_ROAD ? 8 : 4) * resize->height; + break; + + case WID_RV_LEFT_DETAILS: + case WID_RV_RIGHT_DETAILS: + size->height = this->details_height; + break; + + case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: { + StringID str = this->GetWidget(widget)->widget_data; + SetDParam(0, STR_CONFIG_SETTING_ON); + Dimension d = GetStringBoundingBox(str); + SetDParam(0, STR_CONFIG_SETTING_OFF); + d = maxdim(d, GetStringBoundingBox(str)); + d.width += padding.width; + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + + case WID_RV_TRAIN_ENGINEWAGON_TOGGLE: { + StringID str = this->GetWidget(widget)->widget_data; + SetDParam(0, STR_REPLACE_ENGINES); + Dimension d = GetStringBoundingBox(str); + SetDParam(0, STR_REPLACE_WAGONS); + d = maxdim(d, GetStringBoundingBox(str)); + d.width += padding.width; + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + + case WID_RV_INFO_TAB: { + Dimension d = GetStringBoundingBox(STR_REPLACE_NOT_REPLACING); + d = maxdim(d, GetStringBoundingBox(STR_REPLACE_NOT_REPLACING_VEHICLE_SELECTED)); + d.width += WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; + d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + *size = maxdim(*size, d); + break; + } + + case WID_RV_TRAIN_RAILTYPE_DROPDOWN: { + Dimension d = {0, 0}; + for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { + const RailtypeInfo *rti = GetRailTypeInfo(rt); + /* Skip rail type if it has no label */ + if (rti->label == 0) continue; + d = maxdim(d, GetStringBoundingBox(rti->strings.replace_text)); + } + d.width += padding.width; + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + + case WID_RV_START_REPLACE: { + Dimension d = GetStringBoundingBox(STR_REPLACE_VEHICLES_START); + for (int i = 0; _start_replace_dropdown[i] != INVALID_STRING_ID; i++) { + d = maxdim(d, GetStringBoundingBox(_start_replace_dropdown[i])); + } + d.width += padding.width; + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + } + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_RV_CAPTION: + SetDParam(0, STR_REPLACE_VEHICLE_TRAIN + this->window_number); + switch (this->sel_group) { + case ALL_GROUP: + SetDParam(1, STR_GROUP_ALL_TRAINS + this->window_number); + break; + + case DEFAULT_GROUP: + SetDParam(1, STR_GROUP_DEFAULT_TRAINS + this->window_number); + break; + + default: + SetDParam(1, STR_GROUP_NAME); + SetDParam(2, sel_group); + break; + } + break; + + case WID_RV_SORT_DROPDOWN: + SetDParam(0, _engine_sort_listing[this->window_number][this->sort_criteria]); + break; + + case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: { + const Company *c = Company::Get(_local_company); + SetDParam(0, c->settings.renew_keep_length ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF); + break; + } + + case WID_RV_TRAIN_ENGINEWAGON_TOGGLE: + SetDParam(0, this->replace_engines ? STR_REPLACE_ENGINES : STR_REPLACE_WAGONS); + break; + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_RV_SORT_ASCENDING_DESCENDING: + this->DrawSortButtonState(WID_RV_SORT_ASCENDING_DESCENDING, this->descending_sort_order ? SBS_DOWN : SBS_UP); + break; + + case WID_RV_INFO_TAB: { + const Company *c = Company::Get(_local_company); + StringID str; + if (this->sel_engine[0] != INVALID_ENGINE) { + if (!EngineHasReplacementForCompany(c, this->sel_engine[0], this->sel_group)) { + str = STR_REPLACE_NOT_REPLACING; + } else { + bool when_old = false; + EngineID e = EngineReplacementForCompany(c, this->sel_engine[0], this->sel_group, &when_old); + str = when_old ? STR_REPLACE_REPLACING_WHEN_OLD : STR_ENGINE_NAME; + SetDParam(0, e); + } + } else { + str = STR_REPLACE_NOT_REPLACING_VEHICLE_SELECTED; + } + + DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top + WD_FRAMERECT_TOP, str, TC_BLACK, SA_HOR_CENTER); + break; + } + + case WID_RV_LEFT_MATRIX: + case WID_RV_RIGHT_MATRIX: { + int side = (widget == WID_RV_LEFT_MATRIX) ? 0 : 1; + EngineID start = this->vscroll[side]->GetPosition(); // what is the offset for the start (scrolling) + EngineID end = min(this->vscroll[side]->GetCapacity() + start, this->engines[side].Length()); + + /* Do the actual drawing */ + DrawEngineList((VehicleType)this->window_number, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, + &this->engines[side], start, end, this->sel_engine[side], side == 0, this->sel_group); + break; + } + } + } + + virtual void OnPaint() + { + if (this->engines[0].NeedRebuild() || this->engines[1].NeedRebuild()) this->GenerateLists(); + + Company *c = Company::Get(_local_company); + + /* Disable the "Start Replacing" button if: + * Either engines list is empty + * or The selected replacement engine has a replacement (to prevent loops). */ + this->SetWidgetDisabledState(WID_RV_START_REPLACE, + this->sel_engine[0] == INVALID_ENGINE || this->sel_engine[1] == INVALID_ENGINE || EngineReplacementForCompany(c, this->sel_engine[1], this->sel_group) != INVALID_ENGINE); + + /* Disable the "Stop Replacing" button if: + * The left engines list (existing vehicle) is empty + * or The selected vehicle has no replacement set up */ + this->SetWidgetDisabledState(WID_RV_STOP_REPLACE, this->sel_engine[0] == INVALID_ENGINE || !EngineHasReplacementForCompany(c, this->sel_engine[0], this->sel_group)); + + if (this->window_number == VEH_TRAIN) { + /* sets the colour of that art thing */ + this->GetWidget(WID_RV_TRAIN_FLUFF_LEFT)->colour = _company_colours[_local_company]; + this->GetWidget(WID_RV_TRAIN_FLUFF_RIGHT)->colour = _company_colours[_local_company]; + + /* Show the selected railtype in the pulldown menu */ + this->GetWidget(WID_RV_TRAIN_RAILTYPE_DROPDOWN)->widget_data = GetRailTypeInfo(sel_railtype)->strings.replace_text; + } + + this->DrawWidgets(); + + if (!this->IsShaded()) { + int needed_height = this->details_height; + /* Draw details panels. */ + for (int side = 0; side < 2; side++) { + if (this->sel_engine[side] != INVALID_ENGINE) { + NWidgetBase *nwi = this->GetWidget(side == 0 ? WID_RV_LEFT_DETAILS : WID_RV_RIGHT_DETAILS); + int text_end = DrawVehiclePurchaseInfo(nwi->pos_x + WD_FRAMETEXT_LEFT, nwi->pos_x + nwi->current_x - WD_FRAMETEXT_RIGHT, + nwi->pos_y + WD_FRAMERECT_TOP, this->sel_engine[side]); + needed_height = max(needed_height, text_end - (int)nwi->pos_y + WD_FRAMERECT_BOTTOM); + } + } + if (needed_height != this->details_height) { // Details window are not high enough, enlarge them. + this->details_height = needed_height; + this->ReInit(); + return; + } + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_RV_SORT_ASCENDING_DESCENDING: + this->descending_sort_order ^= true; + _engine_sort_last_order[this->window_number] = this->descending_sort_order; + this->engines[1].ForceRebuild(); + this->SetDirty(); + break; + + case WID_RV_SHOW_HIDDEN_ENGINES: + this->show_hidden_engines ^= true; + _engine_sort_show_hidden_engines[this->window_number] = this->show_hidden_engines; + this->engines[1].ForceRebuild(); + this->SetWidgetLoweredState(widget, this->show_hidden_engines); + this->SetDirty(); + break; + + case WID_RV_SORT_DROPDOWN: + DisplayVehicleSortDropDown(this, static_cast(this->window_number), this->sort_criteria, WID_RV_SORT_DROPDOWN); + break; + + case WID_RV_TRAIN_ENGINEWAGON_TOGGLE: + this->replace_engines = !(this->replace_engines); + this->engines[0].ForceRebuild(); + this->reset_sel_engine = true; + this->SetDirty(); + break; + + case WID_RV_TRAIN_RAILTYPE_DROPDOWN: // Railtype selection dropdown menu + ShowDropDownList(this, GetRailTypeDropDownList(true), sel_railtype, WID_RV_TRAIN_RAILTYPE_DROPDOWN); + break; + + case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: // toggle renew_keep_length + DoCommandP(0, GetCompanySettingIndex("company.renew_keep_length"), Company::Get(_local_company)->settings.renew_keep_length ? 0 : 1, CMD_CHANGE_COMPANY_SETTING); + break; + + case WID_RV_START_REPLACE: { // Start replacing + if (this->GetWidget(widget)->ButtonHit(pt)) { + this->HandleButtonClick(WID_RV_START_REPLACE); + ReplaceClick_StartReplace(false); + } else { + bool replacment_when_old = EngineHasReplacementWhenOldForCompany(Company::Get(_local_company), this->sel_engine[0], this->sel_group); + ShowDropDownMenu(this, _start_replace_dropdown, replacment_when_old ? 1 : 0, WID_RV_START_REPLACE, !this->replace_engines ? 1 << 1 : 0, 0); + } + break; + } + + case WID_RV_STOP_REPLACE: { // Stop replacing + EngineID veh_from = this->sel_engine[0]; + DoCommandP(0, this->sel_group << 16, veh_from + (INVALID_ENGINE << 16), CMD_SET_AUTOREPLACE); + break; + } + + case WID_RV_LEFT_MATRIX: + case WID_RV_RIGHT_MATRIX: { + byte click_side; + if (widget == WID_RV_LEFT_MATRIX) { + click_side = 0; + } else { + click_side = 1; + } + uint i = this->vscroll[click_side]->GetScrolledRowFromWidget(pt.y, this, widget); + size_t engine_count = this->engines[click_side].Length(); + + EngineID e = engine_count > i ? this->engines[click_side][i] : INVALID_ENGINE; + if (e == this->sel_engine[click_side]) break; // we clicked the one we already selected + this->sel_engine[click_side] = e; + if (click_side == 0) { + this->engines[1].ForceRebuild(); + this->reset_sel_engine = true; + } + this->SetDirty(); + break; + } + } + } + + virtual void OnDropdownSelect(int widget, int index) + { + switch (widget) { + case WID_RV_SORT_DROPDOWN: + if (this->sort_criteria != index) { + this->sort_criteria = index; + _engine_sort_last_criteria[this->window_number] = this->sort_criteria; + this->engines[1].ForceRebuild(); + this->SetDirty(); + } + break; + + case WID_RV_TRAIN_RAILTYPE_DROPDOWN: { + RailType temp = (RailType)index; + if (temp == sel_railtype) return; // we didn't select a new one. No need to change anything + sel_railtype = temp; + /* Reset scrollbar positions */ + this->vscroll[0]->SetPosition(0); + this->vscroll[1]->SetPosition(0); + /* Rebuild the lists */ + this->engines[0].ForceRebuild(); + this->engines[1].ForceRebuild(); + this->reset_sel_engine = true; + this->SetDirty(); + break; + } + + case WID_RV_START_REPLACE: + this->ReplaceClick_StartReplace(index != 0); + break; + } + } + + virtual void OnResize() + { + this->vscroll[0]->SetCapacityFromWidget(this, WID_RV_LEFT_MATRIX); + this->vscroll[1]->SetCapacityFromWidget(this, WID_RV_RIGHT_MATRIX); + } + + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (data != 0) { + /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ + this->engines[0].ForceRebuild(); + } else { + this->engines[1].ForceRebuild(); + } + } +}; + +static const NWidgetPart _nested_replace_rail_vehicle_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_RV_CAPTION), SetDataTip(STR_REPLACE_VEHICLES_WHITE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), + NWidget(WWT_STICKYBOX, COLOUR_GREY), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PANEL, COLOUR_GREY), + NWidget(WWT_LABEL, COLOUR_GREY), SetDataTip(STR_REPLACE_VEHICLE_VEHICLES_IN_USE, STR_REPLACE_VEHICLE_VEHICLES_IN_USE_TOOLTIP), SetFill(1, 1), SetMinimalSize(0, 12), SetResize(1, 0), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), + NWidget(WWT_LABEL, COLOUR_GREY), SetDataTip(STR_REPLACE_VEHICLE_AVAILABLE_VEHICLES, STR_REPLACE_VEHICLE_AVAILABLE_VEHICLES_TOOLTIP), SetFill(1, 1), SetMinimalSize(0, 12), SetResize(1, 0), + EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 0), EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_SORT_ASCENDING_DESCENDING), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), SetFill(1, 1), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_RV_SORT_DROPDOWN), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_RV_SHOW_HIDDEN_ENGINES), SetDataTip(STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN, STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN_TOOLTIP), + NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 0), SetFill(1, 1), EndContainer(), + EndContainer(), + EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_RV_LEFT_MATRIX), SetMinimalSize(216, 0), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_REPLACE_HELP_LEFT_ARRAY), SetResize(1, 1), SetScrollbar(WID_RV_LEFT_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_RV_LEFT_SCROLLBAR), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_RV_RIGHT_MATRIX), SetMinimalSize(216, 0), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_REPLACE_HELP_RIGHT_ARRAY), SetResize(1, 1), SetScrollbar(WID_RV_RIGHT_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_RV_RIGHT_SCROLLBAR), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_LEFT_DETAILS), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_RIGHT_DETAILS), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_PUSHBUTTON_DROPDOWN, COLOUR_GREY, WID_RV_START_REPLACE), SetMinimalSize(139, 12), SetDataTip(STR_REPLACE_VEHICLES_START, STR_REPLACE_HELP_START_BUTTON), + NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_INFO_TAB), SetMinimalSize(167, 12), SetDataTip(0x0, STR_REPLACE_HELP_REPLACE_INFO_TAB), SetResize(1, 0), + EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_STOP_REPLACE), SetMinimalSize(150, 12), SetDataTip(STR_REPLACE_VEHICLES_STOP, STR_REPLACE_HELP_STOP_BUTTON), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_TRAIN_ENGINEWAGON_TOGGLE), SetMinimalSize(139, 12), SetDataTip(STR_REPLACE_ENGINE_WAGON_SELECT, STR_REPLACE_ENGINE_WAGON_SELECT_HELP), + NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_TRAIN_FLUFF_LEFT), SetMinimalSize(15, 12), EndContainer(), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_RV_TRAIN_RAILTYPE_DROPDOWN), SetMinimalSize(136, 12), SetDataTip(0x0, STR_REPLACE_HELP_RAILTYPE), SetResize(1, 0), + NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_TRAIN_FLUFF_RIGHT), SetMinimalSize(16, 12), EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_TRAIN_WAGONREMOVE_TOGGLE), SetMinimalSize(138, 12), SetDataTip(STR_REPLACE_REMOVE_WAGON, STR_REPLACE_REMOVE_WAGON_HELP), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), +}; + +static WindowDesc _replace_rail_vehicle_desc( + WDP_AUTO, "replace_vehicle_train", 500, 140, + WC_REPLACE_VEHICLE, WC_NONE, + WDF_CONSTRUCTION, + _nested_replace_rail_vehicle_widgets, lengthof(_nested_replace_rail_vehicle_widgets) +); + +static const NWidgetPart _nested_replace_vehicle_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_RV_CAPTION), SetMinimalSize(433, 14), SetDataTip(STR_REPLACE_VEHICLES_WHITE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), + NWidget(WWT_STICKYBOX, COLOUR_GREY), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PANEL, COLOUR_GREY), + NWidget(WWT_LABEL, COLOUR_GREY), SetDataTip(STR_REPLACE_VEHICLE_VEHICLES_IN_USE, STR_REPLACE_VEHICLE_VEHICLES_IN_USE_TOOLTIP), SetFill(1, 1), SetMinimalSize(0, 12), SetResize(1, 0), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), + NWidget(WWT_LABEL, COLOUR_GREY), SetDataTip(STR_REPLACE_VEHICLE_AVAILABLE_VEHICLES, STR_REPLACE_VEHICLE_AVAILABLE_VEHICLES_TOOLTIP), SetFill(1, 1), SetMinimalSize(0, 12), SetResize(1, 0), + EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 0), EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_SORT_ASCENDING_DESCENDING), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_RV_SORT_DROPDOWN), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_RV_SHOW_HIDDEN_ENGINES), SetDataTip(STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN, STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN_TOOLTIP), + NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 0), SetFill(1, 1), EndContainer(), + EndContainer(), + EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_RV_LEFT_MATRIX), SetMinimalSize(216, 0), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_REPLACE_HELP_LEFT_ARRAY), SetResize(1, 1), SetScrollbar(WID_RV_LEFT_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_RV_LEFT_SCROLLBAR), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_RV_RIGHT_MATRIX), SetMinimalSize(216, 0), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_REPLACE_HELP_RIGHT_ARRAY), SetResize(1, 1), SetScrollbar(WID_RV_RIGHT_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_RV_RIGHT_SCROLLBAR), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_LEFT_DETAILS), SetMinimalSize(228, 92), SetResize(1, 0), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_RIGHT_DETAILS), SetMinimalSize(228, 92), SetResize(1, 0), EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_PUSHBUTTON_DROPDOWN, COLOUR_GREY, WID_RV_START_REPLACE), SetMinimalSize(139, 12), SetDataTip(STR_REPLACE_VEHICLES_START, STR_REPLACE_HELP_START_BUTTON), + NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_INFO_TAB), SetMinimalSize(167, 12), SetDataTip(0x0, STR_REPLACE_HELP_REPLACE_INFO_TAB), SetResize(1, 0), EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_STOP_REPLACE), SetMinimalSize(138, 12), SetDataTip(STR_REPLACE_VEHICLES_STOP, STR_REPLACE_HELP_STOP_BUTTON), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), +}; + +static WindowDesc _replace_vehicle_desc( + WDP_AUTO, "replace_vehicle", 456, 118, + WC_REPLACE_VEHICLE, WC_NONE, + WDF_CONSTRUCTION, + _nested_replace_vehicle_widgets, lengthof(_nested_replace_vehicle_widgets) +); + +/** + * Show the autoreplace configuration window for a particular group. + * @param id_g The group to replace the vehicles for. + * @param vehicletype The type of vehicles in the group. + */ +void ShowReplaceGroupVehicleWindow(GroupID id_g, VehicleType vehicletype) +{ + DeleteWindowById(WC_REPLACE_VEHICLE, vehicletype); + new ReplaceVehicleWindow(vehicletype == VEH_TRAIN ? &_replace_rail_vehicle_desc : &_replace_vehicle_desc, vehicletype, id_g); +} diff --git a/src/autoreplace_gui.h b/src/autoreplace_gui.h new file mode 100644 index 0000000..046ac89 --- /dev/null +++ b/src/autoreplace_gui.h @@ -0,0 +1,23 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file autoreplace_gui.h Functions related to the autoreplace GUIs*/ + +#ifndef AUTOREPLACE_GUI_H +#define AUTOREPLACE_GUI_H + +#include "engine_type.h" +#include "group_type.h" +#include "vehicle_type.h" + +void AddRemoveEngineFromAutoreplaceAndBuildWindows(VehicleType type); +void InvalidateAutoreplaceWindow(EngineID e, GroupID id_g); +void ShowReplaceGroupVehicleWindow(GroupID group, VehicleType veh); + +#endif /* AUTOREPLACE_GUI_H */ diff --git a/src/autoreplace_type.h b/src/autoreplace_type.h new file mode 100644 index 0000000..30ba7e2 --- /dev/null +++ b/src/autoreplace_type.h @@ -0,0 +1,22 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file autoreplace_type.h Types related to autoreplacing. */ + +#ifndef AUTOREPLACE_TYPE_H +#define AUTOREPLACE_TYPE_H + +struct EngineRenew; + +/** + * A list to group EngineRenew directives together (such as per-company). + */ +typedef EngineRenew *EngineRenewList; + +#endif /* AUTOREPLACE_TYPE_H */ diff --git a/src/autoslope.h b/src/autoslope.h new file mode 100644 index 0000000..e504610 --- /dev/null +++ b/src/autoslope.h @@ -0,0 +1,53 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file autoslope.h Functions related to autoslope. */ + +#ifndef AUTOSLOPE_H +#define AUTOSLOPE_H + +#include "company_func.h" +#include "depot_func.h" +#include "tile_map.h" + +/** + * Autoslope check for tiles with an entrance on an edge. + * E.g. depots and non-drive-through-road-stops. + * + * The test succeeds if the slope is not steep and at least one corner of the entrance edge is on the TileMaxZ() level. + * + * @note The test does not check if autoslope is enabled at all. + * + * @param tile The tile. + * @param z_new New TileZ. + * @param tileh_new New TileSlope. + * @param entrance Entrance edge. + * @return true iff terraforming is allowed. + */ +static inline bool AutoslopeCheckForEntranceEdge(TileIndex tile, int z_new, Slope tileh_new, DiagDirection entrance) +{ + if (GetTileMaxZ(tile) != z_new + GetSlopeMaxZ(tileh_new)) return false; + return ((tileh_new == SLOPE_FLAT) || CanBuildDepotByTileh(entrance, tileh_new)); +} + +/** + * Tests if autoslope is enabled for _current_company. + * + * Autoslope is disabled for town/industry construction. + * + * @return true iff autoslope is enabled. + */ +static inline bool AutoslopeEnabled() +{ + return (_settings_game.construction.autoslope && + (_current_company < MAX_COMPANIES || + (_current_company == OWNER_NONE && _game_mode == GM_EDITOR))); +} + +#endif /* AUTOSLOPE_H */ diff --git a/src/base_consist.cpp b/src/base_consist.cpp new file mode 100644 index 0000000..2005127 --- /dev/null +++ b/src/base_consist.cpp @@ -0,0 +1,51 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file base_consist.cpp Properties for front vehicles/consists. */ + +#include "stdafx.h" +#include "base_consist.h" +#include "vehicle_base.h" +#include "string_func.h" + +#include "safeguards.h" + +BaseConsist::~BaseConsist() +{ + free(this->name); +} + +/** + * Copy properties of other BaseConsist. + * @param src Source for copying + */ +void BaseConsist::CopyConsistPropertiesFrom(const BaseConsist *src) +{ + if (this == src) return; + + free(this->name); + this->name = src->name != NULL ? stredup(src->name) : NULL; + + this->current_order_time = src->current_order_time; + this->lateness_counter = src->lateness_counter; + this->timetable_start = src->timetable_start; + + this->service_interval = src->service_interval; + + this->cur_real_order_index = src->cur_real_order_index; + this->cur_implicit_order_index = src->cur_implicit_order_index; + + if (HasBit(src->vehicle_flags, VF_TIMETABLE_STARTED)) SetBit(this->vehicle_flags, VF_TIMETABLE_STARTED); + if (HasBit(src->vehicle_flags, VF_AUTOFILL_TIMETABLE)) SetBit(this->vehicle_flags, VF_AUTOFILL_TIMETABLE); + if (HasBit(src->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME)) SetBit(this->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME); + if (HasBit(src->vehicle_flags, VF_SERVINT_IS_PERCENT) != HasBit(this->vehicle_flags, VF_SERVINT_IS_PERCENT)) { + ToggleBit(this->vehicle_flags, VF_SERVINT_IS_PERCENT); + } + if (HasBit(src->vehicle_flags, VF_SERVINT_IS_CUSTOM)) SetBit(this->vehicle_flags, VF_SERVINT_IS_CUSTOM); +} diff --git a/src/base_consist.h b/src/base_consist.h new file mode 100644 index 0000000..2c32301 --- /dev/null +++ b/src/base_consist.h @@ -0,0 +1,41 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file base_consist.h Properties for front vehicles/consists. */ + +#ifndef BASE_CONSIST_H +#define BASE_CONSIST_H + +#include "order_type.h" +#include "date_type.h" +#include "timetable.h" + +/** Various front vehicle properties that are preserved when autoreplacing, using order-backup or switching front engines within a consist. */ +struct BaseConsist { + char *name; ///< Name of vehicle + + /* Used for timetabling. */ + uint32 current_order_time; ///< How many ticks have passed since this order started. + int32 lateness_counter; ///< How many ticks late (or early if negative) this vehicle is. + Date timetable_start; ///< When the vehicle is supposed to start the timetable. + + uint16 service_interval; ///< The interval for (automatic) servicing; either in days or %. + + VehicleOrderID cur_real_order_index;///< The index to the current real (non-implicit) order + VehicleOrderID cur_implicit_order_index;///< The index to the current implicit order + + uint16 vehicle_flags; ///< Used for gradual loading and other miscellaneous things (@see VehicleFlags enum) + + BaseConsist() : name(NULL) {} + virtual ~BaseConsist(); + + void CopyConsistPropertiesFrom(const BaseConsist *src); +}; + +#endif /* BASE_CONSIST_H */ diff --git a/src/base_media_base.h b/src/base_media_base.h new file mode 100644 index 0000000..d5de6c3 --- /dev/null +++ b/src/base_media_base.h @@ -0,0 +1,298 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file base_media_base.h Generic functions for replacing base data (graphics, sounds). */ + +#ifndef BASE_MEDIA_BASE_H +#define BASE_MEDIA_BASE_H + +#include "fileio_func.h" +#include "core/smallmap_type.hpp" +#include "gfx_type.h" +#include "textfile_type.h" +#include "textfile_gui.h" + +/* Forward declare these; can't do 'struct X' in functions as older GCCs barf on that */ +struct IniFile; +struct ContentInfo; + +/** Structure holding filename and MD5 information about a single file */ +struct MD5File { + /** The result of a checksum check */ + enum ChecksumResult { + CR_MATCH, ///< The file did exist and the md5 checksum did match + CR_MISMATCH, ///< The file did exist, just the md5 checksum did not match + CR_NO_FILE, ///< The file did not exist + }; + + const char *filename; ///< filename + uint8 hash[16]; ///< md5 sum of the file + const char *missing_warning; ///< warning when this file is missing + + ChecksumResult CheckMD5(Subdirectory subdir, size_t max_size) const; +}; + +/** + * Information about a single base set. + * @tparam T the real class we're going to be + * @tparam Tnum_files the number of files in the set + * @tparam Tsearch_in_tars whether to search in the tars or not + */ +template +struct BaseSet { + typedef SmallMap TranslatedStrings; + + /** Number of files in this set */ + static const size_t NUM_FILES = Tnum_files; + + /** Whether to search in the tars or not. */ + static const bool SEARCH_IN_TARS = Tsearch_in_tars; + + /** Internal names of the files in this set. */ + static const char * const *file_names; + + const char *name; ///< The name of the base set + TranslatedStrings description; ///< Description of the base set + uint32 shortname; ///< Four letter short variant of the name + uint32 version; ///< The version of this base set + bool fallback; ///< This set is a fallback set, i.e. it should be used only as last resort + + MD5File files[NUM_FILES]; ///< All files part of this set + uint found_files; ///< Number of the files that could be found + uint valid_files; ///< Number of the files that could be found and are valid + + T *next; ///< The next base set in this list + + /** Free everything we allocated */ + ~BaseSet() + { + free(this->name); + + for (TranslatedStrings::iterator iter = this->description.Begin(); iter != this->description.End(); iter++) { + free(iter->first); + free(iter->second); + } + + for (uint i = 0; i < NUM_FILES; i++) { + free(this->files[i].filename); + free(this->files[i].missing_warning); + } + + delete this->next; + } + + /** + * Get the number of missing files. + * @return the number + */ + int GetNumMissing() const + { + return Tnum_files - this->found_files; + } + + /** + * Get the number of invalid files. + * @note a missing file is invalid too! + * @return the number + */ + int GetNumInvalid() const + { + return Tnum_files - this->valid_files; + } + + bool FillSetDetails(IniFile *ini, const char *path, const char *full_filename, bool allow_empty_filename = true); + + /** + * Get the description for the given ISO code. + * It falls back to the first two characters of the ISO code in case + * no match could be made with the full ISO code. If even then the + * matching fails the default is returned. + * @param isocode the isocode to search for + * @return the description + */ + const char *GetDescription(const char *isocode = NULL) const + { + if (isocode != NULL) { + /* First the full ISO code */ + for (TranslatedStrings::const_iterator iter = this->description.Begin(); iter != this->description.End(); iter++) { + if (strcmp(iter->first, isocode) == 0) return iter->second; + } + /* Then the first two characters */ + for (TranslatedStrings::const_iterator iter = this->description.Begin(); iter != this->description.End(); iter++) { + if (strncmp(iter->first, isocode, 2) == 0) return iter->second; + } + } + /* Then fall back */ + return this->description.Begin()->second; + } + + /** + * Calculate and check the MD5 hash of the supplied file. + * @param file The file get the hash of. + * @param subdir The sub directory to get the files from. + * @return + * - #CR_MATCH if the MD5 hash matches + * - #CR_MISMATCH if the MD5 does not match + * - #CR_NO_FILE if the file misses + */ + static MD5File::ChecksumResult CheckMD5(const MD5File *file, Subdirectory subdir) + { + return file->CheckMD5(subdir, SIZE_MAX); + } + + /** + * Search a textfile file next to this base media. + * @param type The type of the textfile to search for. + * @return The filename for the textfile, \c NULL otherwise. + */ + const char *GetTextfile(TextfileType type) const + { + for (uint i = 0; i < NUM_FILES; i++) { + const char *textfile = ::GetTextfile(type, BASESET_DIR, this->files[i].filename); + if (textfile != NULL) { + return textfile; + } + } + return NULL; + } +}; + +/** + * Base for all base media (graphics, sounds) + * @tparam Tbase_set the real set we're going to be + */ +template +class BaseMedia : FileScanner { +protected: + static Tbase_set *available_sets; ///< All available sets + static Tbase_set *duplicate_sets; ///< All sets that aren't available, but needed for not downloading base sets when a newer version than the one on BaNaNaS is loaded. + static const Tbase_set *used_set; ///< The currently used set + + /* virtual */ bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename); + + /** + * Get the extension that is used to identify this set. + * @return the extension + */ + static const char *GetExtension(); +public: + /** The set as saved in the config file. */ + static const char *ini_set; + + /** + * Determine the graphics pack that has to be used. + * The one with the most correct files wins. + * @return true if a best set has been found. + */ + static bool DetermineBestSet(); + + /** Do the scan for files. */ + static uint FindSets() + { + BaseMedia fs; + /* Searching in tars is only done in the old "data" directories basesets. */ + uint num = fs.Scan(GetExtension(), Tbase_set::SEARCH_IN_TARS ? OLD_DATA_DIR : OLD_GM_DIR, Tbase_set::SEARCH_IN_TARS); + return num + fs.Scan(GetExtension(), BASESET_DIR, Tbase_set::SEARCH_IN_TARS); + } + + static Tbase_set *GetAvailableSets(); + + static bool SetSet(const char *name); + static char *GetSetsList(char *p, const char *last); + static int GetNumSets(); + static int GetIndexOfUsedSet(); + static const Tbase_set *GetSet(int index); + static const Tbase_set *GetUsedSet(); + + /** + * Check whether we have an set with the exact characteristics as ci. + * @param ci the characteristics to search on (shortname and md5sum) + * @param md5sum whether to check the MD5 checksum + * @return true iff we have an set matching. + */ + static bool HasSet(const ContentInfo *ci, bool md5sum); +}; + +/** + * Check whether there's a base set matching some information. + * @param ci The content info to compare it to. + * @param md5sum Should the MD5 checksum be tested as well? + * @param s The list with sets. + * @return The filename of the first file of the base set, or \c NULL if there is no match. + */ +template +const char *TryGetBaseSetFile(const ContentInfo *ci, bool md5sum, const Tbase_set *s); + +/** Types of graphics in the base graphics set */ +enum GraphicsFileType { + GFT_BASE, ///< Base sprites for all climates + GFT_LOGOS, ///< Logos, landscape icons and original terrain generator sprites + GFT_ARCTIC, ///< Landscape replacement sprites for arctic + GFT_TROPICAL, ///< Landscape replacement sprites for tropical + GFT_TOYLAND, ///< Landscape replacement sprites for toyland + GFT_EXTRA, ///< Extra sprites that were not part of the original sprites + MAX_GFT, ///< We are looking for this amount of GRFs +}; + +/** Blitter type for base graphics sets. */ +enum BlitterType { + BLT_8BPP, ///< Base set has 8 bpp sprites only. + BLT_32BPP, ///< Base set has both 8 bpp and 32 bpp sprites. +}; + +/** All data of a graphics set. */ +struct GraphicsSet : BaseSet { + PaletteType palette; ///< Palette of this graphics set + BlitterType blitter; ///< Blitter of this graphics set + + bool FillSetDetails(struct IniFile *ini, const char *path, const char *full_filename); + + static MD5File::ChecksumResult CheckMD5(const MD5File *file, Subdirectory subdir); +}; + +/** All data/functions related with replacing the base graphics. */ +class BaseGraphics : public BaseMedia { +public: +}; + +/** All data of a sounds set. */ +struct SoundsSet : BaseSet { +}; + +/** All data/functions related with replacing the base sounds */ +class BaseSounds : public BaseMedia { +public: +}; + +/** Maximum number of songs in the 'class' playlists. */ +static const uint NUM_SONGS_CLASS = 10; +/** Number of classes for songs */ +static const uint NUM_SONG_CLASSES = 3; +/** Maximum number of songs in the full playlist; theme song + the classes */ +static const uint NUM_SONGS_AVAILABLE = 1 + NUM_SONG_CLASSES * NUM_SONGS_CLASS; + +/** Maximum number of songs in the (custom) playlist */ +static const uint NUM_SONGS_PLAYLIST = 32; + +/** All data of a music set. */ +struct MusicSet : BaseSet { + /** The name of the different songs. */ + char song_name[NUM_SONGS_AVAILABLE][32]; + byte track_nr[NUM_SONGS_AVAILABLE]; + byte num_available; + + bool FillSetDetails(struct IniFile *ini, const char *path, const char *full_filename); +}; + +/** All data/functions related with replacing the base music */ +class BaseMusic : public BaseMedia { +public: +}; + +#endif /* BASE_MEDIA_BASE_H */ diff --git a/src/base_media_func.h b/src/base_media_func.h new file mode 100644 index 0000000..e3678d5 --- /dev/null +++ b/src/base_media_func.h @@ -0,0 +1,414 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** + * @file base_media_func.h Generic function implementations for base data (graphics, sounds). + * @note You should _never_ include this file due to the SET_TYPE define. + */ + +#include "base_media_base.h" +#include "debug.h" +#include "ini_type.h" +#include "string_func.h" + +template /* static */ const char *BaseMedia::ini_set; +template /* static */ const Tbase_set *BaseMedia::used_set; +template /* static */ Tbase_set *BaseMedia::available_sets; +template /* static */ Tbase_set *BaseMedia::duplicate_sets; + +/** + * Try to read a single piece of metadata and return false if it doesn't exist. + * @param name the name of the item to fetch. + */ +#define fetch_metadata(name) \ + item = metadata->GetItem(name, false); \ + if (item == NULL || StrEmpty(item->value)) { \ + DEBUG(grf, 0, "Base " SET_TYPE "set detail loading: %s field missing.", name); \ + DEBUG(grf, 0, " Is %s readable for the user running OpenTTD?", full_filename); \ + return false; \ + } + +/** + * Read the set information from a loaded ini. + * @param ini the ini to read from + * @param path the path to this ini file (for filenames) + * @param full_filename the full filename of the loaded file (for error reporting purposes) + * @param allow_empty_filename empty filenames are valid + * @return true if loading was successful. + */ +template +bool BaseSet::FillSetDetails(IniFile *ini, const char *path, const char *full_filename, bool allow_empty_filename) +{ + memset(this, 0, sizeof(*this)); + + IniGroup *metadata = ini->GetGroup("metadata"); + IniItem *item; + + fetch_metadata("name"); + this->name = stredup(item->value); + + fetch_metadata("description"); + this->description[stredup("")] = stredup(item->value); + + /* Add the translations of the descriptions too. */ + for (const IniItem *item = metadata->item; item != NULL; item = item->next) { + if (strncmp("description.", item->name, 12) != 0) continue; + + this->description[stredup(item->name + 12)] = stredup(item->value); + } + + fetch_metadata("shortname"); + for (uint i = 0; item->value[i] != '\0' && i < 4; i++) { + this->shortname |= ((uint8)item->value[i]) << (i * 8); + } + + fetch_metadata("version"); + this->version = atoi(item->value); + + item = metadata->GetItem("fallback", false); + this->fallback = (item != NULL && strcmp(item->value, "0") != 0 && strcmp(item->value, "false") != 0); + + /* For each of the file types we want to find the file, MD5 checksums and warning messages. */ + IniGroup *files = ini->GetGroup("files"); + IniGroup *md5s = ini->GetGroup("md5s"); + IniGroup *origin = ini->GetGroup("origin"); + for (uint i = 0; i < Tnum_files; i++) { + MD5File *file = &this->files[i]; + /* Find the filename first. */ + item = files->GetItem(BaseSet::file_names[i], false); + if (item == NULL || (item->value == NULL && !allow_empty_filename)) { + DEBUG(grf, 0, "No " SET_TYPE " file for: %s (in %s)", BaseSet::file_names[i], full_filename); + return false; + } + + const char *filename = item->value; + if (filename == NULL) { + file->filename = NULL; + /* If we list no file, that file must be valid */ + this->valid_files++; + this->found_files++; + continue; + } + + file->filename = str_fmt("%s%s", path, filename); + + /* Then find the MD5 checksum */ + item = md5s->GetItem(filename, false); + if (item == NULL || item->value == NULL) { + DEBUG(grf, 0, "No MD5 checksum specified for: %s (in %s)", filename, full_filename); + return false; + } + char *c = item->value; + for (uint i = 0; i < sizeof(file->hash) * 2; i++, c++) { + uint j; + if ('0' <= *c && *c <= '9') { + j = *c - '0'; + } else if ('a' <= *c && *c <= 'f') { + j = *c - 'a' + 10; + } else if ('A' <= *c && *c <= 'F') { + j = *c - 'A' + 10; + } else { + DEBUG(grf, 0, "Malformed MD5 checksum specified for: %s (in %s)", filename, full_filename); + return false; + } + if (i % 2 == 0) { + file->hash[i / 2] = j << 4; + } else { + file->hash[i / 2] |= j; + } + } + + /* Then find the warning message when the file's missing */ + item = origin->GetItem(filename, false); + if (item == NULL) item = origin->GetItem("default", false); + if (item == NULL) { + DEBUG(grf, 1, "No origin warning message specified for: %s", filename); + file->missing_warning = stredup(""); + } else { + file->missing_warning = stredup(item->value); + } + + switch (T::CheckMD5(file, BASESET_DIR)) { + case MD5File::CR_MATCH: + this->valid_files++; + this->found_files++; + break; + + case MD5File::CR_MISMATCH: + DEBUG(grf, 1, "MD5 checksum mismatch for: %s (in %s)", filename, full_filename); + this->found_files++; + break; + + case MD5File::CR_NO_FILE: + DEBUG(grf, 1, "The file %s specified in %s is missing", filename, full_filename); + break; + } + } + + return true; +} + +template +bool BaseMedia::AddFile(const char *filename, size_t basepath_length, const char *tar_filename) +{ + bool ret = false; + DEBUG(grf, 1, "Checking %s for base " SET_TYPE " set", filename); + + Tbase_set *set = new Tbase_set(); + IniFile *ini = new IniFile(); + ini->LoadFromDisk(filename, BASESET_DIR); + + char *path = stredup(filename + basepath_length); + char *psep = strrchr(path, PATHSEPCHAR); + if (psep != NULL) { + psep[1] = '\0'; + } else { + *path = '\0'; + } + + if (set->FillSetDetails(ini, path, filename)) { + Tbase_set *duplicate = NULL; + for (Tbase_set *c = BaseMedia::available_sets; c != NULL; c = c->next) { + if (strcmp(c->name, set->name) == 0 || c->shortname == set->shortname) { + duplicate = c; + break; + } + } + if (duplicate != NULL) { + /* The more complete set takes precedence over the version number. */ + if ((duplicate->valid_files == set->valid_files && duplicate->version >= set->version) || + duplicate->valid_files > set->valid_files) { + DEBUG(grf, 1, "Not adding %s (%i) as base " SET_TYPE " set (duplicate, %s)", set->name, set->version, + duplicate->valid_files > set->valid_files ? "less valid files" : "lower version"); + set->next = BaseMedia::duplicate_sets; + BaseMedia::duplicate_sets = set; + } else { + Tbase_set **prev = &BaseMedia::available_sets; + while (*prev != duplicate) prev = &(*prev)->next; + + *prev = set; + set->next = duplicate->next; + + /* If the duplicate set is currently used (due to rescanning this can happen) + * update the currently used set to the new one. This will 'lie' about the + * version number until a new game is started which isn't a big problem */ + if (BaseMedia::used_set == duplicate) BaseMedia::used_set = set; + + DEBUG(grf, 1, "Removing %s (%i) as base " SET_TYPE " set (duplicate, %s)", duplicate->name, duplicate->version, + duplicate->valid_files < set->valid_files ? "less valid files" : "lower version"); + duplicate->next = BaseMedia::duplicate_sets; + BaseMedia::duplicate_sets = duplicate; + ret = true; + } + } else { + Tbase_set **last = &BaseMedia::available_sets; + while (*last != NULL) last = &(*last)->next; + + *last = set; + ret = true; + } + if (ret) { + DEBUG(grf, 1, "Adding %s (%i) as base " SET_TYPE " set", set->name, set->version); + } + } else { + delete set; + } + free(path); + + delete ini; + return ret; +} + +/** + * Set the set to be used. + * @param name of the set to use + * @return true if it could be loaded + */ +template +/* static */ bool BaseMedia::SetSet(const char *name) +{ + extern void CheckExternalFiles(); + + if (StrEmpty(name)) { + if (!BaseMedia::DetermineBestSet()) return false; + CheckExternalFiles(); + return true; + } + + for (const Tbase_set *s = BaseMedia::available_sets; s != NULL; s = s->next) { + if (strcmp(name, s->name) == 0) { + BaseMedia::used_set = s; + CheckExternalFiles(); + return true; + } + } + return false; +} + +/** + * Returns a list with the sets. + * @param p where to print to + * @param last the last character to print to + * @return the last printed character + */ +template +/* static */ char *BaseMedia::GetSetsList(char *p, const char *last) +{ + p += seprintf(p, last, "List of " SET_TYPE " sets:\n"); + for (const Tbase_set *s = BaseMedia::available_sets; s != NULL; s = s->next) { + p += seprintf(p, last, "%18s: %s", s->name, s->GetDescription()); + int invalid = s->GetNumInvalid(); + if (invalid != 0) { + int missing = s->GetNumMissing(); + if (missing == 0) { + p += seprintf(p, last, " (%i corrupt file%s)\n", invalid, invalid == 1 ? "" : "s"); + } else { + p += seprintf(p, last, " (unusable: %i missing file%s)\n", missing, missing == 1 ? "" : "s"); + } + } else { + p += seprintf(p, last, "\n"); + } + } + p += seprintf(p, last, "\n"); + + return p; +} + +#if defined(ENABLE_NETWORK) +#include "network/network_content.h" + +template const char *TryGetBaseSetFile(const ContentInfo *ci, bool md5sum, const Tbase_set *s) +{ + for (; s != NULL; s = s->next) { + if (s->GetNumMissing() != 0) continue; + + if (s->shortname != ci->unique_id) continue; + if (!md5sum) return s->files[0].filename; + + byte md5[16]; + memset(md5, 0, sizeof(md5)); + for (uint i = 0; i < Tbase_set::NUM_FILES; i++) { + for (uint j = 0; j < sizeof(md5); j++) { + md5[j] ^= s->files[i].hash[j]; + } + } + if (memcmp(md5, ci->md5sum, sizeof(md5)) == 0) return s->files[0].filename; + } + return NULL; +} + +template +/* static */ bool BaseMedia::HasSet(const ContentInfo *ci, bool md5sum) +{ + return (TryGetBaseSetFile(ci, md5sum, BaseMedia::available_sets) != NULL) || + (TryGetBaseSetFile(ci, md5sum, BaseMedia::duplicate_sets) != NULL); +} + +#else + +template +const char *TryGetBaseSetFile(const ContentInfo *ci, bool md5sum, const Tbase_set *s) +{ + return NULL; +} + +template +/* static */ bool BaseMedia::HasSet(const ContentInfo *ci, bool md5sum) +{ + return false; +} + +#endif /* ENABLE_NETWORK */ + +/** + * Count the number of available graphics sets. + * @return the number of sets + */ +template +/* static */ int BaseMedia::GetNumSets() +{ + int n = 0; + for (const Tbase_set *s = BaseMedia::available_sets; s != NULL; s = s->next) { + if (s != BaseMedia::used_set && s->GetNumMissing() != 0) continue; + n++; + } + return n; +} + +/** + * Get the index of the currently active graphics set + * @return the current set's index + */ +template +/* static */ int BaseMedia::GetIndexOfUsedSet() +{ + int n = 0; + for (const Tbase_set *s = BaseMedia::available_sets; s != NULL; s = s->next) { + if (s == BaseMedia::used_set) return n; + if (s->GetNumMissing() != 0) continue; + n++; + } + return -1; +} + +/** + * Get the name of the graphics set at the specified index + * @return the name of the set + */ +template +/* static */ const Tbase_set *BaseMedia::GetSet(int index) +{ + for (const Tbase_set *s = BaseMedia::available_sets; s != NULL; s = s->next) { + if (s != BaseMedia::used_set && s->GetNumMissing() != 0) continue; + if (index == 0) return s; + index--; + } + error("Base" SET_TYPE "::GetSet(): index %d out of range", index); +} + +/** + * Return the used set. + * @return the used set. + */ +template +/* static */ const Tbase_set *BaseMedia::GetUsedSet() +{ + return BaseMedia::used_set; +} + +/** + * Return the available sets. + * @return The available sets. + */ +template +/* static */ Tbase_set *BaseMedia::GetAvailableSets() +{ + return BaseMedia::available_sets; +} + +/** + * Force instantiation of methods so we don't get linker errors. + * @param repl_type the type of the BaseMedia to instantiate + * @param set_type the type of the BaseSet to instantiate + */ +#define INSTANTIATE_BASE_MEDIA_METHODS(repl_type, set_type) \ + template const char *repl_type::ini_set; \ + template const char *repl_type::GetExtension(); \ + template bool repl_type::AddFile(const char *filename, size_t pathlength, const char *tar_filename); \ + template bool repl_type::HasSet(const struct ContentInfo *ci, bool md5sum); \ + template bool repl_type::SetSet(const char *name); \ + template char *repl_type::GetSetsList(char *p, const char *last); \ + template int repl_type::GetNumSets(); \ + template int repl_type::GetIndexOfUsedSet(); \ + template const set_type *repl_type::GetSet(int index); \ + template const set_type *repl_type::GetUsedSet(); \ + template bool repl_type::DetermineBestSet(); \ + template set_type *repl_type::GetAvailableSets(); \ + template const char *TryGetBaseSetFile(const ContentInfo *ci, bool md5sum, const set_type *s); + diff --git a/src/base_station_base.h b/src/base_station_base.h new file mode 100644 index 0000000..53e104a --- /dev/null +++ b/src/base_station_base.h @@ -0,0 +1,255 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file base_station_base.h Base classes/functions for base stations. */ + +#ifndef BASE_STATION_BASE_H +#define BASE_STATION_BASE_H + +#include "core/pool_type.hpp" +#include "command_type.h" +#include "viewport_type.h" +#include "station_map.h" + +typedef Pool StationPool; +extern StationPool _station_pool; + +struct StationSpecList { + const StationSpec *spec; + uint32 grfid; ///< GRF ID of this custom station + uint8 localidx; ///< Station ID within GRF of station +}; + + +/** StationRect - used to track station spread out rectangle - cheaper than scanning whole map */ +struct StationRect : public Rect { + enum StationRectMode + { + ADD_TEST = 0, + ADD_TRY, + ADD_FORCE + }; + + StationRect(); + void MakeEmpty(); + bool PtInExtendedRect(int x, int y, int distance = 0) const; + bool IsEmpty() const; + CommandCost BeforeAddTile(TileIndex tile, StationRectMode mode); + CommandCost BeforeAddRect(TileIndex tile, int w, int h, StationRectMode mode); + bool AfterRemoveTile(BaseStation *st, TileIndex tile); + bool AfterRemoveRect(BaseStation *st, TileArea ta); + + static bool ScanForStationTiles(StationID st_id, int left_a, int top_a, int right_a, int bottom_a); + + StationRect& operator = (const Rect &src); +}; + +/** Base class for all station-ish types */ +struct BaseStation : StationPool::PoolItem<&_station_pool> { + TileIndex xy; ///< Base tile of the station + ViewportSign sign; ///< NOSAVE: Dimensions of sign + byte delete_ctr; ///< Delete counter. If greater than 0 then it is decremented until it reaches 0; the waypoint is then is deleted. + + char *name; ///< Custom name + StringID string_id; ///< Default name (town area) of station + + Town *town; ///< The town this station is associated with + OwnerByte owner; ///< The owner of this station + StationFacilityByte facilities; ///< The facilities that this station has + + uint8 num_specs; ///< Number of specs in the speclist + StationSpecList *speclist; ///< List of station specs of this station + + Date build_date; ///< Date of construction + + uint16 random_bits; ///< Random bits assigned to this station + byte waiting_triggers; ///< Waiting triggers (NewGRF) for this station + uint8 cached_anim_triggers; ///< NOSAVE: Combined animation trigger bitmask, used to determine if trigger processing should happen. + uint32 cached_cargo_triggers; ///< NOSAVE: Combined cargo trigger bitmask + + TileArea train_station; ///< Tile area the train 'station' part covers + StationRect rect; ///< NOSAVE: Station spread out rectangle maintained by StationRect::xxx() functions + + /** + * Initialize the base station. + * @param tile The location of the station sign + */ + BaseStation(TileIndex tile) : + xy(tile), + train_station(INVALID_TILE, 0, 0) + { + } + + virtual ~BaseStation(); + + /** + * Check whether a specific tile belongs to this station. + * @param tile the tile to check + * @return true if the tile belongs to this station + */ + virtual bool TileBelongsToRailStation(TileIndex tile) const = 0; + + /** + * Helper function to get a NewGRF variable that isn't implemented by the base class. + * @param object the resolver object related to this query + * @param variable that is queried + * @param parameter parameter for that variable + * @param available will return false if ever the variable asked for does not exist + * @return the value stored in the corresponding variable + */ + virtual uint32 GetNewGRFVariable(const struct ResolverObject &object, byte variable, byte parameter, bool *available) const = 0; + + /** + * Update the coordinated of the sign (as shown in the viewport). + */ + virtual void UpdateVirtCoord() = 0; + + /** + * Get the tile area for a given station type. + * @param ta tile area to fill. + * @param type the type of the area + */ + virtual void GetTileArea(TileArea *ta, StationType type) const = 0; + + + /** + * Obtain the length of a platform + * @pre tile must be a rail station tile + * @param tile A tile that contains the platform in question + * @return The length of the platform + */ + virtual uint GetPlatformLength(TileIndex tile) const = 0; + + /** + * Determines the REMAINING length of a platform, starting at (and including) + * the given tile. + * @param tile the tile from which to start searching. Must be a rail station tile + * @param dir The direction in which to search. + * @return The platform length + */ + virtual uint GetPlatformLength(TileIndex tile, DiagDirection dir) const = 0; + + /** + * Get the base station belonging to a specific tile. + * @param tile The tile to get the base station from. + * @return the station associated with that tile. + */ + static inline BaseStation *GetByTile(TileIndex tile) + { + return BaseStation::Get(GetStationIndex(tile)); + } + + /** + * Check whether the base station currently is in use; in use means + * that it is not scheduled for deletion and that it still has some + * facilities left. + * @return true if still in use + */ + inline bool IsInUse() const + { + return (this->facilities & ~FACIL_WAYPOINT) != 0; + } + + static void PostDestructor(size_t index); +}; + +#define FOR_ALL_BASE_STATIONS(var) FOR_ALL_ITEMS_FROM(BaseStation, station_index, var, 0) + +/** + * Class defining several overloaded accessors so we don't + * have to cast base stations that often + */ +template +struct SpecializedStation : public BaseStation { + static const StationFacility EXPECTED_FACIL = Tis_waypoint ? FACIL_WAYPOINT : FACIL_NONE; ///< Specialized type + + /** + * Set station type correctly + * @param tile The base tile of the station. + */ + inline SpecializedStation(TileIndex tile) : + BaseStation(tile) + { + this->facilities = EXPECTED_FACIL; + } + + /** + * Helper for checking whether the given station is of this type. + * @param st the station to check. + * @return true if the station is the type we expect it to be. + */ + static inline bool IsExpected(const BaseStation *st) + { + return (st->facilities & FACIL_WAYPOINT) == EXPECTED_FACIL; + } + + /** + * Tests whether given index is a valid index for station of this type + * @param index tested index + * @return is this index valid index of T? + */ + static inline bool IsValidID(size_t index) + { + return BaseStation::IsValidID(index) && IsExpected(BaseStation::Get(index)); + } + + /** + * Gets station with given index + * @return pointer to station with given index casted to T * + */ + static inline T *Get(size_t index) + { + return (T *)BaseStation::Get(index); + } + + /** + * Returns station if the index is a valid index for this station type + * @return pointer to station with given index if it's a station of this type + */ + static inline T *GetIfValid(size_t index) + { + return IsValidID(index) ? Get(index) : NULL; + } + + /** + * Get the station belonging to a specific tile. + * @param tile The tile to get the station from. + * @return the station associated with that tile. + */ + static inline T *GetByTile(TileIndex tile) + { + return GetIfValid(GetStationIndex(tile)); + } + + /** + * Converts a BaseStation to SpecializedStation with type checking. + * @param st BaseStation pointer + * @return pointer to SpecializedStation + */ + static inline T *From(BaseStation *st) + { + assert(IsExpected(st)); + return (T *)st; + } + + /** + * Converts a const BaseStation to const SpecializedStation with type checking. + * @param st BaseStation pointer + * @return pointer to SpecializedStation + */ + static inline const T *From(const BaseStation *st) + { + assert(IsExpected(st)); + return (const T *)st; + } +}; + +#define FOR_ALL_BASE_STATIONS_OF_TYPE(name, var) FOR_ALL_ITEMS_FROM(name, station_index, var, 0) if (name::IsExpected(var)) + +#endif /* BASE_STATION_BASE_H */ diff --git a/src/blitter/32bpp_anim.cpp b/src/blitter/32bpp_anim.cpp new file mode 100644 index 0000000..a3083e4 --- /dev/null +++ b/src/blitter/32bpp_anim.cpp @@ -0,0 +1,513 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file 32bpp_anim.cpp Implementation of the optimized 32 bpp blitter with animation support. */ + +#include "../stdafx.h" +#include "../video/video_driver.hpp" +#include "32bpp_anim.hpp" + +#include "../table/sprites.h" + +#include "../safeguards.h" + +/** Instantiation of the 32bpp with animation blitter factory. */ +static FBlitter_32bppAnim iFBlitter_32bppAnim; + +template +inline void Blitter_32bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom) +{ + const SpriteData *src = (const SpriteData *)bp->sprite; + + const Colour *src_px = (const Colour *)(src->data + src->offset[zoom][0]); + const uint16 *src_n = (const uint16 *)(src->data + src->offset[zoom][1]); + + for (uint i = bp->skip_top; i != 0; i--) { + src_px = (const Colour *)((const byte *)src_px + *(const uint32 *)src_px); + src_n = (const uint16 *)((const byte *)src_n + *(const uint32 *)src_n); + } + + Colour *dst = (Colour *)bp->dst + bp->top * bp->pitch + bp->left; + uint16 *anim = this->anim_buf + ((uint32 *)bp->dst - (uint32 *)_screen.dst_ptr) + bp->top * this->anim_buf_width + bp->left; + + const byte *remap = bp->remap; // store so we don't have to access it via bp everytime + + for (int y = 0; y < bp->height; y++) { + Colour *dst_ln = dst + bp->pitch; + uint16 *anim_ln = anim + this->anim_buf_width; + + const Colour *src_px_ln = (const Colour *)((const byte *)src_px + *(const uint32 *)src_px); + src_px++; + + const uint16 *src_n_ln = (const uint16 *)((const byte *)src_n + *(const uint32 *)src_n); + src_n += 2; + + Colour *dst_end = dst + bp->skip_left; + + uint n; + + while (dst < dst_end) { + n = *src_n++; + + if (src_px->a == 0) { + dst += n; + src_px ++; + src_n++; + + if (dst > dst_end) anim += dst - dst_end; + } else { + if (dst + n > dst_end) { + uint d = dst_end - dst; + src_px += d; + src_n += d; + + dst = dst_end - bp->skip_left; + dst_end = dst + bp->width; + + n = min(n - d, (uint)bp->width); + goto draw; + } + dst += n; + src_px += n; + src_n += n; + } + } + + dst -= bp->skip_left; + dst_end -= bp->skip_left; + + dst_end += bp->width; + + while (dst < dst_end) { + n = min(*src_n++, (uint)(dst_end - dst)); + + if (src_px->a == 0) { + anim += n; + dst += n; + src_px++; + src_n++; + continue; + } + + draw:; + + switch (mode) { + case BM_COLOUR_REMAP: + if (src_px->a == 255) { + do { + uint m = *src_n; + /* In case the m-channel is zero, do not remap this pixel in any way */ + if (m == 0) { + *dst = src_px->data; + *anim = 0; + } else { + uint r = remap[GB(m, 0, 8)]; + *anim = r | (m & 0xFF00); + if (r != 0) *dst = this->AdjustBrightness(this->LookupColourInPalette(r), GB(m, 8, 8)); + } + anim++; + dst++; + src_px++; + src_n++; + } while (--n != 0); + } else { + do { + uint m = *src_n; + if (m == 0) { + *dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst); + *anim = 0; + } else { + uint r = remap[GB(m, 0, 8)]; + *anim = 0; + if (r != 0) *dst = ComposeColourPANoCheck(this->AdjustBrightness(this->LookupColourInPalette(r), GB(m, 8, 8)), src_px->a, *dst); + } + anim++; + dst++; + src_px++; + src_n++; + } while (--n != 0); + } + break; + + case BM_CRASH_REMAP: + if (src_px->a == 255) { + do { + uint m = *src_n; + if (m == 0) { + uint8 g = MakeDark(src_px->r, src_px->g, src_px->b); + *dst = ComposeColourRGBA(g, g, g, src_px->a, *dst); + *anim = 0; + } else { + uint r = remap[GB(m, 0, 8)]; + *anim = r | (m & 0xFF00); + if (r != 0) *dst = this->AdjustBrightness(this->LookupColourInPalette(r), GB(m, 8, 8)); + } + anim++; + dst++; + src_px++; + src_n++; + } while (--n != 0); + } else { + do { + uint m = *src_n; + if (m == 0) { + if (src_px->a != 0) { + uint8 g = MakeDark(src_px->r, src_px->g, src_px->b); + *dst = ComposeColourRGBA(g, g, g, src_px->a, *dst); + *anim = 0; + } + } else { + uint r = remap[GB(m, 0, 8)]; + *anim = 0; + if (r != 0) *dst = ComposeColourPANoCheck(this->AdjustBrightness(this->LookupColourInPalette(r), GB(m, 8, 8)), src_px->a, *dst); + } + anim++; + dst++; + src_px++; + src_n++; + } while (--n != 0); + } + break; + + + case BM_BLACK_REMAP: + do { + *dst++ = Colour(0, 0, 0); + *anim++ = 0; + src_px++; + src_n++; + } while (--n != 0); + break; + + case BM_TRANSPARENT: + /* TODO -- We make an assumption here that the remap in fact is transparency, not some colour. + * This is never a problem with the code we produce, but newgrfs can make it fail... or at least: + * we produce a result the newgrf maker didn't expect ;) */ + + /* Make the current colour a bit more black, so it looks like this image is transparent */ + src_n += n; + if (src_px->a == 255) { + src_px += n; + do { + *dst = MakeTransparent(*dst, 3, 4); + *anim = 0; + anim++; + dst++; + } while (--n != 0); + } else { + do { + *dst = MakeTransparent(*dst, (256 * 4 - src_px->a), 256 * 4); + *anim = 0; + anim++; + dst++; + src_px++; + } while (--n != 0); + } + break; + + default: + if (src_px->a == 255) { + do { + /* Compiler assumes pointer aliasing, can't optimise this on its own */ + uint m = GB(*src_n, 0, 8); + /* Above PALETTE_ANIM_START is palette animation */ + *anim++ = *src_n; + *dst++ = (m >= PALETTE_ANIM_START) ? this->AdjustBrightness(this->LookupColourInPalette(m), GB(*src_n, 8, 8)) : src_px->data; + src_px++; + src_n++; + } while (--n != 0); + } else { + do { + uint m = GB(*src_n, 0, 8); + *anim++ = 0; + if (m >= PALETTE_ANIM_START) { + *dst = ComposeColourPANoCheck(this->AdjustBrightness(this->LookupColourInPalette(m), GB(*src_n, 8, 8)), src_px->a, *dst); + } else { + *dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst); + } + dst++; + src_px++; + src_n++; + } while (--n != 0); + } + break; + } + } + + anim = anim_ln; + dst = dst_ln; + src_px = src_px_ln; + src_n = src_n_ln; + } +} + +void Blitter_32bppAnim::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) +{ + if (_screen_disable_anim) { + /* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent Draw() */ + Blitter_32bppOptimized::Draw(bp, mode, zoom); + return; + } + + switch (mode) { + default: NOT_REACHED(); + case BM_NORMAL: Draw (bp, zoom); return; + case BM_COLOUR_REMAP: Draw(bp, zoom); return; + case BM_TRANSPARENT: Draw (bp, zoom); return; + case BM_CRASH_REMAP: Draw (bp, zoom); return; + case BM_BLACK_REMAP: Draw (bp, zoom); return; + } +} + +void Blitter_32bppAnim::DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) +{ + if (_screen_disable_anim) { + /* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent DrawColourMappingRect() */ + Blitter_32bppOptimized::DrawColourMappingRect(dst, width, height, pal); + return; + } + + Colour *udst = (Colour *)dst; + uint16 *anim; + + anim = this->anim_buf + ((uint32 *)dst - (uint32 *)_screen.dst_ptr); + + if (pal == PALETTE_TO_TRANSPARENT) { + do { + for (int i = 0; i != width; i++) { + *udst = MakeTransparent(*udst, 154); + *anim = 0; + udst++; + anim++; + } + udst = udst - width + _screen.pitch; + anim = anim - width + this->anim_buf_width; + } while (--height); + return; + } + if (pal == PALETTE_NEWSPAPER) { + do { + for (int i = 0; i != width; i++) { + *udst = MakeGrey(*udst); + *anim = 0; + udst++; + anim++; + } + udst = udst - width + _screen.pitch; + anim = anim - width + this->anim_buf_width; + } while (--height); + return; + } + + DEBUG(misc, 0, "32bpp blitter doesn't know how to draw this colour table ('%d')", pal); +} + +void Blitter_32bppAnim::SetPixel(void *video, int x, int y, uint8 colour) +{ + *((Colour *)video + x + y * _screen.pitch) = LookupColourInPalette(colour); + + /* Set the colour in the anim-buffer too, if we are rendering to the screen */ + if (_screen_disable_anim) return; + this->anim_buf[((uint32 *)video - (uint32 *)_screen.dst_ptr) + x + y * this->anim_buf_width] = colour | (DEFAULT_BRIGHTNESS << 8); +} + +void Blitter_32bppAnim::DrawRect(void *video, int width, int height, uint8 colour) +{ + if (_screen_disable_anim) { + /* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent DrawRect() */ + Blitter_32bppOptimized::DrawRect(video, width, height, colour); + return; + } + + Colour colour32 = LookupColourInPalette(colour); + uint16 *anim_line; + + anim_line = ((uint32 *)video - (uint32 *)_screen.dst_ptr) + this->anim_buf; + + do { + Colour *dst = (Colour *)video; + uint16 *anim = anim_line; + + for (int i = width; i > 0; i--) { + *dst = colour32; + /* Set the colour in the anim-buffer too */ + *anim = colour | (DEFAULT_BRIGHTNESS << 8); + dst++; + anim++; + } + video = (uint32 *)video + _screen.pitch; + anim_line += this->anim_buf_width; + } while (--height); +} + +void Blitter_32bppAnim::CopyFromBuffer(void *video, const void *src, int width, int height) +{ + assert(!_screen_disable_anim); + assert(video >= _screen.dst_ptr && video <= (uint32 *)_screen.dst_ptr + _screen.width + _screen.height * _screen.pitch); + Colour *dst = (Colour *)video; + const uint32 *usrc = (const uint32 *)src; + uint16 *anim_line = ((uint32 *)video - (uint32 *)_screen.dst_ptr) + this->anim_buf; + + for (; height > 0; height--) { + /* We need to keep those for palette animation. */ + Colour *dst_pal = dst; + uint16 *anim_pal = anim_line; + + memcpy(dst, usrc, width * sizeof(uint32)); + usrc += width; + dst += _screen.pitch; + /* Copy back the anim-buffer */ + memcpy(anim_line, usrc, width * sizeof(uint16)); + usrc = (const uint32 *)((const uint16 *)usrc + width); + anim_line += this->anim_buf_width; + + /* Okay, it is *very* likely that the image we stored is using + * the wrong palette animated colours. There are two things we + * can do to fix this. The first is simply reviewing the whole + * screen after we copied the buffer, i.e. run PaletteAnimate, + * however that forces a full screen redraw which is expensive + * for just the cursor. This just copies the implementation of + * palette animation, much cheaper though slightly nastier. */ + for (int i = 0; i < width; i++) { + uint colour = GB(*anim_pal, 0, 8); + if (colour >= PALETTE_ANIM_START) { + /* Update this pixel */ + *dst_pal = this->AdjustBrightness(LookupColourInPalette(colour), GB(*anim_pal, 8, 8)); + } + dst_pal++; + anim_pal++; + } + } +} + +void Blitter_32bppAnim::CopyToBuffer(const void *video, void *dst, int width, int height) +{ + assert(!_screen_disable_anim); + assert(video >= _screen.dst_ptr && video <= (uint32 *)_screen.dst_ptr + _screen.width + _screen.height * _screen.pitch); + uint32 *udst = (uint32 *)dst; + const uint32 *src = (const uint32 *)video; + const uint16 *anim_line; + + if (this->anim_buf == NULL) return; + + anim_line = ((const uint32 *)video - (uint32 *)_screen.dst_ptr) + this->anim_buf; + + for (; height > 0; height--) { + memcpy(udst, src, width * sizeof(uint32)); + src += _screen.pitch; + udst += width; + /* Copy the anim-buffer */ + memcpy(udst, anim_line, width * sizeof(uint16)); + udst = (uint32 *)((uint16 *)udst + width); + anim_line += this->anim_buf_width; + } +} + +void Blitter_32bppAnim::ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) +{ + assert(!_screen_disable_anim); + assert(video >= _screen.dst_ptr && video <= (uint32 *)_screen.dst_ptr + _screen.width + _screen.height * _screen.pitch); + uint16 *dst, *src; + + /* We need to scroll the anim-buffer too */ + if (scroll_y > 0) { + dst = this->anim_buf + left + (top + height - 1) * this->anim_buf_width; + src = dst - scroll_y * this->anim_buf_width; + + /* Adjust left & width */ + if (scroll_x >= 0) { + dst += scroll_x; + } else { + src -= scroll_x; + } + + uint tw = width + (scroll_x >= 0 ? -scroll_x : scroll_x); + uint th = height - scroll_y; + for (; th > 0; th--) { + memcpy(dst, src, tw * sizeof(uint16)); + src -= this->anim_buf_width; + dst -= this->anim_buf_width; + } + } else { + /* Calculate pointers */ + dst = this->anim_buf + left + top * this->anim_buf_width; + src = dst - scroll_y * this->anim_buf_width; + + /* Adjust left & width */ + if (scroll_x >= 0) { + dst += scroll_x; + } else { + src -= scroll_x; + } + + /* the y-displacement may be 0 therefore we have to use memmove, + * because source and destination may overlap */ + uint tw = width + (scroll_x >= 0 ? -scroll_x : scroll_x); + uint th = height + scroll_y; + for (; th > 0; th--) { + memmove(dst, src, tw * sizeof(uint16)); + src += this->anim_buf_width; + dst += this->anim_buf_width; + } + } + + Blitter_32bppBase::ScrollBuffer(video, left, top, width, height, scroll_x, scroll_y); +} + +int Blitter_32bppAnim::BufferSize(int width, int height) +{ + return width * height * (sizeof(uint32) + sizeof(uint16)); +} + +void Blitter_32bppAnim::PaletteAnimate(const Palette &palette) +{ + assert(!_screen_disable_anim); + + this->palette = palette; + /* If first_dirty is 0, it is for 8bpp indication to send the new + * palette. However, only the animation colours might possibly change. + * Especially when going between toyland and non-toyland. */ + assert(this->palette.first_dirty == PALETTE_ANIM_START || this->palette.first_dirty == 0); + + const uint16 *anim = this->anim_buf; + Colour *dst = (Colour *)_screen.dst_ptr; + + /* Let's walk the anim buffer and try to find the pixels */ + for (int y = this->anim_buf_height; y != 0 ; y--) { + for (int x = this->anim_buf_width; x != 0 ; x--) { + uint colour = GB(*anim, 0, 8); + if (colour >= PALETTE_ANIM_START) { + /* Update this pixel */ + *dst = this->AdjustBrightness(LookupColourInPalette(colour), GB(*anim, 8, 8)); + } + dst++; + anim++; + } + dst += _screen.pitch - this->anim_buf_width; + } + + /* Make sure the backend redraws the whole screen */ + VideoDriver::GetInstance()->MakeDirty(0, 0, _screen.width, _screen.height); +} + +Blitter::PaletteAnimation Blitter_32bppAnim::UsePaletteAnimation() +{ + return Blitter::PALETTE_ANIMATION_BLITTER; +} + +void Blitter_32bppAnim::PostResize() +{ + if (_screen.width != this->anim_buf_width || _screen.height != this->anim_buf_height) { + /* The size of the screen changed; we can assume we can wipe all data from our buffer */ + free(this->anim_buf); + this->anim_buf = CallocT(_screen.width * _screen.height); + this->anim_buf_width = _screen.width; + this->anim_buf_height = _screen.height; + } +} diff --git a/src/blitter/32bpp_anim.hpp b/src/blitter/32bpp_anim.hpp new file mode 100644 index 0000000..e707c44 --- /dev/null +++ b/src/blitter/32bpp_anim.hpp @@ -0,0 +1,65 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file 32bpp_anim.hpp A 32 bpp blitter with animation support. */ + +#ifndef BLITTER_32BPP_ANIM_HPP +#define BLITTER_32BPP_ANIM_HPP + +#include "32bpp_optimized.hpp" + +/** The optimised 32 bpp blitter with palette animation. */ +class Blitter_32bppAnim : public Blitter_32bppOptimized { +protected: + uint16 *anim_buf; ///< In this buffer we keep track of the 8bpp indexes so we can do palette animation + int anim_buf_width; ///< The width of the animation buffer. + int anim_buf_height; ///< The height of the animation buffer. + Palette palette; ///< The current palette. + +public: + Blitter_32bppAnim() : + anim_buf(NULL), + anim_buf_width(0), + anim_buf_height(0) + {} + + /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); + /* virtual */ void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal); + /* virtual */ void SetPixel(void *video, int x, int y, uint8 colour); + /* virtual */ void DrawRect(void *video, int width, int height, uint8 colour); + /* virtual */ void CopyFromBuffer(void *video, const void *src, int width, int height); + /* virtual */ void CopyToBuffer(const void *video, void *dst, int width, int height); + /* virtual */ void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y); + /* virtual */ int BufferSize(int width, int height); + /* virtual */ void PaletteAnimate(const Palette &palette); + /* virtual */ Blitter::PaletteAnimation UsePaletteAnimation(); + + /* virtual */ const char *GetName() { return "32bpp-anim"; } + /* virtual */ int GetBytesPerPixel() { return 6; } + /* virtual */ void PostResize(); + + /** + * Look up the colour in the current palette. + */ + inline Colour LookupColourInPalette(uint index) + { + return this->palette.palette[index]; + } + + template void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom); +}; + +/** Factory for the 32bpp blitter with animation. */ +class FBlitter_32bppAnim : public BlitterFactory { +public: + FBlitter_32bppAnim() : BlitterFactory("32bpp-anim", "32bpp Animation Blitter (palette animation)") {} + /* virtual */ Blitter *CreateInstance() { return new Blitter_32bppAnim(); } +}; + +#endif /* BLITTER_32BPP_ANIM_HPP */ diff --git a/src/blitter/32bpp_anim_sse4.cpp b/src/blitter/32bpp_anim_sse4.cpp new file mode 100644 index 0000000..7d4b66f --- /dev/null +++ b/src/blitter/32bpp_anim_sse4.cpp @@ -0,0 +1,415 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file 32bpp_sse4_anim.cpp Implementation of the SSE4 32 bpp blitter with animation support. */ + +#ifdef WITH_SSE + +#include "../stdafx.h" +#include "../video/video_driver.hpp" +#include "../table/sprites.h" +#include "32bpp_anim_sse4.hpp" +#include "32bpp_sse_func.hpp" + +#include "../safeguards.h" + +/** Instantiation of the SSE4 32bpp blitter factory. */ +static FBlitter_32bppSSE4_Anim iFBlitter_32bppSSE4_Anim; + +/** + * Draws a sprite to a (screen) buffer. It is templated to allow faster operation. + * + * @tparam mode blitter mode + * @param bp further blitting parameters + * @param zoom zoom level at which we are drawing + */ +IGNORE_UNINITIALIZED_WARNING_START +template +inline void Blitter_32bppSSE4_Anim::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom) +{ + const byte * const remap = bp->remap; + Colour *dst_line = (Colour *) bp->dst + bp->top * bp->pitch + bp->left; + uint16 *anim_line = this->anim_buf + ((uint32 *)bp->dst - (uint32 *)_screen.dst_ptr) + bp->top * this->anim_buf_width + bp->left; + int effective_width = bp->width; + + /* Find where to start reading in the source sprite. */ + const Blitter_32bppSSE_Base::SpriteData * const sd = (const Blitter_32bppSSE_Base::SpriteData *) bp->sprite; + const SpriteInfo * const si = &sd->infos[zoom]; + const MapValue *src_mv_line = (const MapValue *) &sd->data[si->mv_offset] + bp->skip_top * si->sprite_width; + const Colour *src_rgba_line = (const Colour *) ((const byte *) &sd->data[si->sprite_offset] + bp->skip_top * si->sprite_line_size); + + if (read_mode != RM_WITH_MARGIN) { + src_rgba_line += bp->skip_left; + src_mv_line += bp->skip_left; + } + const MapValue *src_mv = src_mv_line; + + /* Load these variables into register before loop. */ + const __m128i a_cm = ALPHA_CONTROL_MASK; + const __m128i pack_low_cm = PACK_LOW_CONTROL_MASK; + const __m128i tr_nom_base = TRANSPARENT_NOM_BASE; + + for (int y = bp->height; y != 0; y--) { + Colour *dst = dst_line; + const Colour *src = src_rgba_line + META_LENGTH; + if (mode != BM_TRANSPARENT) src_mv = src_mv_line; + uint16 *anim = anim_line; + + if (read_mode == RM_WITH_MARGIN) { + assert(bt_last == BT_NONE); // or you must ensure block type is preserved + anim += src_rgba_line[0].data; + src += src_rgba_line[0].data; + dst += src_rgba_line[0].data; + if (mode != BM_TRANSPARENT) src_mv += src_rgba_line[0].data; + const int width_diff = si->sprite_width - bp->width; + effective_width = bp->width - (int) src_rgba_line[0].data; + const int delta_diff = (int) src_rgba_line[1].data - width_diff; + const int new_width = effective_width - delta_diff; + effective_width = delta_diff > 0 ? new_width : effective_width; + if (effective_width <= 0) goto next_line; + } + + switch (mode) { + default: + if (!translucent) { + for (uint x = (uint) effective_width; x > 0; x--) { + if (src->a) { + if (animated) { + *anim = *(const uint16*) src_mv; + *dst = (src_mv->m >= PALETTE_ANIM_START) ? AdjustBrightneSSE(this->LookupColourInPalette(src_mv->m), src_mv->v) : src->data; + } else { + *anim = 0; + *dst = *src; + } + } + if (animated) src_mv++; + anim++; + src++; + dst++; + } + break; + } + + for (uint x = (uint) effective_width/2; x != 0; x--) { + uint32 mvX2 = *((uint32 *) const_cast(src_mv)); + __m128i srcABCD = _mm_loadl_epi64((const __m128i*) src); + __m128i dstABCD = _mm_loadl_epi64((__m128i*) dst); + + if (animated) { + /* Remap colours. */ + const byte m0 = mvX2; + if (m0 >= PALETTE_ANIM_START) { + const Colour c0 = (this->LookupColourInPalette(m0).data & 0x00FFFFFF) | (src[0].data & 0xFF000000); + InsertFirstUint32(AdjustBrightneSSE(c0, (byte) (mvX2 >> 8)).data, srcABCD); + } + const byte m1 = mvX2 >> 16; + if (m1 >= PALETTE_ANIM_START) { + const Colour c1 = (this->LookupColourInPalette(m1).data & 0x00FFFFFF) | (src[1].data & 0xFF000000); + InsertSecondUint32(AdjustBrightneSSE(c1, (byte) (mvX2 >> 24)).data, srcABCD); + } + + /* Update anim buffer. */ + const byte a0 = src[0].a; + const byte a1 = src[1].a; + uint32 anim01 = 0; + if (a0 == 255) { + if (a1 == 255) { + *(uint32*) anim = mvX2; + goto bmno_full_opacity; + } + anim01 = (uint16) mvX2; + } else if (a0 == 0) { + if (a1 == 0) { + goto bmno_full_transparency; + } else { + if (a1 == 255) anim[1] = (uint16) (mvX2 >> 16); + goto bmno_alpha_blend; + } + } + if (a1 > 0) { + if (a1 == 255) anim01 |= mvX2 & 0xFFFF0000; + *(uint32*) anim = anim01; + } else { + anim[0] = (uint16) anim01; + } + } else { + if (src[0].a) anim[0] = 0; + if (src[1].a) anim[1] = 0; + } + + /* Blend colours. */ +bmno_alpha_blend: + srcABCD = AlphaBlendTwoPixels(srcABCD, dstABCD, a_cm, pack_low_cm); +bmno_full_opacity: + _mm_storel_epi64((__m128i *) dst, srcABCD); +bmno_full_transparency: + src_mv += 2; + src += 2; + anim += 2; + dst += 2; + } + + if ((bt_last == BT_NONE && effective_width & 1) || bt_last == BT_ODD) { + if (src->a == 0) { + } else if (src->a == 255) { + *anim = *(const uint16*) src_mv; + *dst = (src_mv->m >= PALETTE_ANIM_START) ? AdjustBrightneSSE(LookupColourInPalette(src_mv->m), src_mv->v) : *src; + } else { + *anim = 0; + __m128i srcABCD; + __m128i dstABCD = _mm_cvtsi32_si128(dst->data); + if (src_mv->m >= PALETTE_ANIM_START) { + Colour colour = AdjustBrightneSSE(LookupColourInPalette(src_mv->m), src_mv->v); + colour.a = src->a; + srcABCD = _mm_cvtsi32_si128(colour.data); + } else { + srcABCD = _mm_cvtsi32_si128(src->data); + } + dst->data = _mm_cvtsi128_si32(AlphaBlendTwoPixels(srcABCD, dstABCD, a_cm, pack_low_cm)); + } + } + break; + + case BM_COLOUR_REMAP: + for (uint x = (uint) effective_width / 2; x != 0; x--) { + uint32 mvX2 = *((uint32 *) const_cast(src_mv)); + __m128i srcABCD = _mm_loadl_epi64((const __m128i*) src); + __m128i dstABCD = _mm_loadl_epi64((__m128i*) dst); + + /* Remap colours. */ + const uint m0 = (byte) mvX2; + const uint r0 = remap[m0]; + const uint m1 = (byte) (mvX2 >> 16); + const uint r1 = remap[m1]; + if (mvX2 & 0x00FF00FF) { + #define CMOV_REMAP(m_colour, m_colour_init, m_src, m_m) \ + /* Written so the compiler uses CMOV. */ \ + Colour m_colour = m_colour_init; \ + { \ + const Colour srcm = (Colour) (m_src); \ + const uint m = (byte) (m_m); \ + const uint r = remap[m]; \ + const Colour cmap = (this->LookupColourInPalette(r).data & 0x00FFFFFF) | (srcm.data & 0xFF000000); \ + m_colour = r == 0 ? m_colour : cmap; \ + m_colour = m != 0 ? m_colour : srcm; \ + } +#ifdef _SQ64 + uint64 srcs = _mm_cvtsi128_si64(srcABCD); + uint64 dsts; + if (animated) dsts = _mm_cvtsi128_si64(dstABCD); + uint64 remapped_src = 0; + CMOV_REMAP(c0, animated ? dsts : 0, srcs, mvX2); + remapped_src = c0.data; + CMOV_REMAP(c1, animated ? dsts >> 32 : 0, srcs >> 32, mvX2 >> 16); + remapped_src |= (uint64) c1.data << 32; + srcABCD = _mm_cvtsi64_si128(remapped_src); +#else + Colour remapped_src[2]; + CMOV_REMAP(c0, animated ? _mm_cvtsi128_si32(dstABCD) : 0, _mm_cvtsi128_si32(srcABCD), mvX2); + remapped_src[0] = c0.data; + CMOV_REMAP(c1, animated ? dst[1] : 0, src[1], mvX2 >> 16); + remapped_src[1] = c1.data; + srcABCD = _mm_loadl_epi64((__m128i*) &remapped_src); +#endif + + if ((mvX2 & 0xFF00FF00) != 0x80008000) srcABCD = AdjustBrightnessOfTwoPixels(srcABCD, mvX2); + } + + /* Update anim buffer. */ + if (animated) { + const byte a0 = src[0].a; + const byte a1 = src[1].a; + uint32 anim01 = mvX2 & 0xFF00FF00; + if (a0 == 255) { + anim01 |= r0; + if (a1 == 255) { + *(uint32*) anim = anim01 | (r1 << 16); + goto bmcr_full_opacity; + } + } else if (a0 == 0) { + if (a1 == 0) { + goto bmcr_full_transparency; + } else { + if (a1 == 255) { + anim[1] = r1 | (anim01 >> 16); + } + goto bmcr_alpha_blend; + } + } + if (a1 > 0) { + if (a1 == 255) anim01 |= r1 << 16; + *(uint32*) anim = anim01; + } else { + anim[0] = (uint16) anim01; + } + } else { + if (src[0].a) anim[0] = 0; + if (src[1].a) anim[1] = 0; + } + + /* Blend colours. */ +bmcr_alpha_blend: + srcABCD = AlphaBlendTwoPixels(srcABCD, dstABCD, a_cm, pack_low_cm); +bmcr_full_opacity: + _mm_storel_epi64((__m128i *) dst, srcABCD); +bmcr_full_transparency: + src_mv += 2; + dst += 2; + src += 2; + anim += 2; + } + + if ((bt_last == BT_NONE && effective_width & 1) || bt_last == BT_ODD) { + /* In case the m-channel is zero, do not remap this pixel in any way. */ + __m128i srcABCD; + if (src->a == 0) break; + if (src_mv->m) { + const uint r = remap[src_mv->m]; + *anim = (animated && src->a == 255) ? r | ((uint16) src_mv->v << 8 ) : 0; + if (r != 0) { + Colour remapped_colour = AdjustBrightneSSE(this->LookupColourInPalette(r), src_mv->v); + if (src->a == 255) { + *dst = remapped_colour; + } else { + remapped_colour.a = src->a; + srcABCD = _mm_cvtsi32_si128(remapped_colour.data); + goto bmcr_alpha_blend_single; + } + } + } else { + *anim = 0; + srcABCD = _mm_cvtsi32_si128(src->data); + if (src->a < 255) { +bmcr_alpha_blend_single: + __m128i dstABCD = _mm_cvtsi32_si128(dst->data); + srcABCD = AlphaBlendTwoPixels(srcABCD, dstABCD, a_cm, pack_low_cm); + } + dst->data = _mm_cvtsi128_si32(srcABCD); + } + } + break; + + case BM_TRANSPARENT: + /* Make the current colour a bit more black, so it looks like this image is transparent. */ + for (uint x = (uint) bp->width / 2; x > 0; x--) { + __m128i srcABCD = _mm_loadl_epi64((const __m128i*) src); + __m128i dstABCD = _mm_loadl_epi64((__m128i*) dst); + _mm_storel_epi64((__m128i *) dst, DarkenTwoPixels(srcABCD, dstABCD, a_cm, tr_nom_base)); + src += 2; + dst += 2; + anim += 2; + if (src[-2].a) anim[-2] = 0; + if (src[-1].a) anim[-1] = 0; + } + + if ((bt_last == BT_NONE && bp->width & 1) || bt_last == BT_ODD) { + __m128i srcABCD = _mm_cvtsi32_si128(src->data); + __m128i dstABCD = _mm_cvtsi32_si128(dst->data); + dst->data = _mm_cvtsi128_si32(DarkenTwoPixels(srcABCD, dstABCD, a_cm, tr_nom_base)); + if (src[0].a) anim[0] = 0; + } + break; + + case BM_CRASH_REMAP: + for (uint x = (uint) bp->width; x > 0; x--) { + if (src_mv->m == 0) { + if (src->a != 0) { + uint8 g = MakeDark(src->r, src->g, src->b); + *dst = ComposeColourRGBA(g, g, g, src->a, *dst); + *anim = 0; + } + } else { + uint r = remap[src_mv->m]; + if (r != 0) *dst = ComposeColourPANoCheck(this->AdjustBrightness(this->LookupColourInPalette(r), src_mv->v), src->a, *dst); + } + src_mv++; + dst++; + src++; + anim++; + } + break; + + case BM_BLACK_REMAP: + for (uint x = (uint) bp->width; x > 0; x--) { + if (src->a != 0) { + *dst = Colour(0, 0, 0); + *anim = 0; + } + src_mv++; + dst++; + src++; + anim++; + } + break; + } + +next_line: + if (mode != BM_TRANSPARENT) src_mv_line += si->sprite_width; + src_rgba_line = (const Colour*) ((const byte*) src_rgba_line + si->sprite_line_size); + dst_line += bp->pitch; + anim_line += this->anim_buf_width; + } +} +IGNORE_UNINITIALIZED_WARNING_STOP + +/** + * Draws a sprite to a (screen) buffer. Calls adequate templated function. + * + * @param bp further blitting parameters + * @param mode blitter mode + * @param zoom zoom level at which we are drawing + */ +void Blitter_32bppSSE4_Anim::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) +{ + const Blitter_32bppSSE_Base::SpriteFlags sprite_flags = ((const Blitter_32bppSSE_Base::SpriteData *) bp->sprite)->flags; + switch (mode) { + default: { +bm_normal: + if (bp->skip_left != 0 || bp->width <= MARGIN_NORMAL_THRESHOLD) { + const BlockType bt_last = (BlockType) (bp->width & 1); + if (bt_last == BT_EVEN) { + if (sprite_flags & SF_NO_ANIM) Draw(bp, zoom); + else Draw(bp, zoom); + } else { + if (sprite_flags & SF_NO_ANIM) Draw(bp, zoom); + else Draw(bp, zoom); + } + } else { +#ifdef _SQ64 + if (sprite_flags & SF_TRANSLUCENT) { + if (sprite_flags & SF_NO_ANIM) Draw(bp, zoom); + else Draw(bp, zoom); + } else { + if (sprite_flags & SF_NO_ANIM) Draw(bp, zoom); + else Draw(bp, zoom); + } +#else + if (sprite_flags & SF_NO_ANIM) Draw(bp, zoom); + else Draw(bp, zoom); +#endif + } + break; + } + case BM_COLOUR_REMAP: + if (sprite_flags & SF_NO_REMAP) goto bm_normal; + if (bp->skip_left != 0 || bp->width <= MARGIN_REMAP_THRESHOLD) { + if (sprite_flags & SF_NO_ANIM) Draw(bp, zoom); + else Draw(bp, zoom); + } else { + if (sprite_flags & SF_NO_ANIM) Draw(bp, zoom); + else Draw(bp, zoom); + } + break; + case BM_TRANSPARENT: Draw(bp, zoom); return; + case BM_CRASH_REMAP: Draw(bp, zoom); return; + case BM_BLACK_REMAP: Draw(bp, zoom); return; + } +} + +#endif /* WITH_SSE */ diff --git a/src/blitter/32bpp_anim_sse4.hpp b/src/blitter/32bpp_anim_sse4.hpp new file mode 100644 index 0000000..e2d4cfc --- /dev/null +++ b/src/blitter/32bpp_anim_sse4.hpp @@ -0,0 +1,53 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file 32bpp_sse4_anim.hpp A SSE4 32 bpp blitter with animation support. */ + +#ifndef BLITTER_32BPP_SSE4_ANIM_HPP +#define BLITTER_32BPP_SSE4_ANIM_HPP + +#ifdef WITH_SSE + +#ifndef SSE_VERSION +#define SSE_VERSION 4 +#endif + +#ifndef FULL_ANIMATION +#define FULL_ANIMATION 1 +#endif + +#include "32bpp_anim.hpp" +#include "32bpp_sse4.hpp" + +#undef MARGIN_NORMAL_THRESHOLD +#define MARGIN_NORMAL_THRESHOLD 4 + +/** The SSE4 32 bpp blitter with palette animation. */ +class Blitter_32bppSSE4_Anim FINAL : public Blitter_32bppAnim, public Blitter_32bppSSE_Base { +private: + +public: + template + /* virtual */ void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom); + /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); + /* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) { + return Blitter_32bppSSE_Base::Encode(sprite, allocator); + } + /* virtual */ const char *GetName() { return "32bpp-sse4-anim"; } +}; + +/** Factory for the SSE4 32 bpp blitter (with palette animation). */ +class FBlitter_32bppSSE4_Anim: public BlitterFactory { +public: + FBlitter_32bppSSE4_Anim() : BlitterFactory("32bpp-sse4-anim", "SSE4 Blitter (palette animation)", HasCPUIDFlag(1, 2, 19)) {} + /* virtual */ Blitter *CreateInstance() { return new Blitter_32bppSSE4_Anim(); } +}; + +#endif /* WITH_SSE */ +#endif /* BLITTER_32BPP_SSE4_ANIM_HPP */ diff --git a/src/blitter/32bpp_base.cpp b/src/blitter/32bpp_base.cpp new file mode 100644 index 0000000..26dd2f0 --- /dev/null +++ b/src/blitter/32bpp_base.cpp @@ -0,0 +1,149 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file 32bpp_base.cpp Implementation of base for 32 bpp blitters. */ + +#include "../stdafx.h" +#include "32bpp_base.hpp" + +#include "../safeguards.h" + +void *Blitter_32bppBase::MoveTo(void *video, int x, int y) +{ + return (uint32 *)video + x + y * _screen.pitch; +} + +void Blitter_32bppBase::SetPixel(void *video, int x, int y, uint8 colour) +{ + *((Colour *)video + x + y * _screen.pitch) = LookupColourInPalette(colour); +} + +void Blitter_32bppBase::DrawRect(void *video, int width, int height, uint8 colour) +{ + Colour colour32 = LookupColourInPalette(colour); + + do { + Colour *dst = (Colour *)video; + for (int i = width; i > 0; i--) { + *dst = colour32; + dst++; + } + video = (uint32 *)video + _screen.pitch; + } while (--height); +} + +void Blitter_32bppBase::CopyFromBuffer(void *video, const void *src, int width, int height) +{ + uint32 *dst = (uint32 *)video; + const uint32 *usrc = (const uint32 *)src; + + for (; height > 0; height--) { + memcpy(dst, usrc, width * sizeof(uint32)); + usrc += width; + dst += _screen.pitch; + } +} + +void Blitter_32bppBase::CopyToBuffer(const void *video, void *dst, int width, int height) +{ + uint32 *udst = (uint32 *)dst; + const uint32 *src = (const uint32 *)video; + + for (; height > 0; height--) { + memcpy(udst, src, width * sizeof(uint32)); + src += _screen.pitch; + udst += width; + } +} + +void Blitter_32bppBase::CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) +{ + uint32 *udst = (uint32 *)dst; + const uint32 *src = (const uint32 *)video; + + for (; height > 0; height--) { + memcpy(udst, src, width * sizeof(uint32)); + src += _screen.pitch; + udst += dst_pitch; + } +} + +void Blitter_32bppBase::ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) +{ + const uint32 *src; + uint32 *dst; + + if (scroll_y > 0) { + /* Calculate pointers */ + dst = (uint32 *)video + left + (top + height - 1) * _screen.pitch; + src = dst - scroll_y * _screen.pitch; + + /* Decrease height and increase top */ + top += scroll_y; + height -= scroll_y; + assert(height > 0); + + /* Adjust left & width */ + if (scroll_x >= 0) { + dst += scroll_x; + left += scroll_x; + width -= scroll_x; + } else { + src -= scroll_x; + width += scroll_x; + } + + for (int h = height; h > 0; h--) { + memcpy(dst, src, width * sizeof(uint32)); + src -= _screen.pitch; + dst -= _screen.pitch; + } + } else { + /* Calculate pointers */ + dst = (uint32 *)video + left + top * _screen.pitch; + src = dst - scroll_y * _screen.pitch; + + /* Decrease height. (scroll_y is <=0). */ + height += scroll_y; + assert(height > 0); + + /* Adjust left & width */ + if (scroll_x >= 0) { + dst += scroll_x; + left += scroll_x; + width -= scroll_x; + } else { + src -= scroll_x; + width += scroll_x; + } + + /* the y-displacement may be 0 therefore we have to use memmove, + * because source and destination may overlap */ + for (int h = height; h > 0; h--) { + memmove(dst, src, width * sizeof(uint32)); + src += _screen.pitch; + dst += _screen.pitch; + } + } +} + +int Blitter_32bppBase::BufferSize(int width, int height) +{ + return width * height * sizeof(uint32); +} + +void Blitter_32bppBase::PaletteAnimate(const Palette &palette) +{ + /* By default, 32bpp doesn't have palette animation */ +} + +Blitter::PaletteAnimation Blitter_32bppBase::UsePaletteAnimation() +{ + return Blitter::PALETTE_ANIMATION_NONE; +} diff --git a/src/blitter/32bpp_base.hpp b/src/blitter/32bpp_base.hpp new file mode 100644 index 0000000..26c3dee --- /dev/null +++ b/src/blitter/32bpp_base.hpp @@ -0,0 +1,176 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file 32bpp_base.hpp Base for all 32 bits blitters. */ + +#ifndef BLITTER_32BPP_BASE_HPP +#define BLITTER_32BPP_BASE_HPP + +#include "base.hpp" +#include "../core/bitmath_func.hpp" +#include "../core/math_func.hpp" +#include "../gfx_func.h" + +/** Base for all 32bpp blitters. */ +class Blitter_32bppBase : public Blitter { +public: + /* virtual */ uint8 GetScreenDepth() { return 32; } + /* virtual */ void *MoveTo(void *video, int x, int y); + /* virtual */ void SetPixel(void *video, int x, int y, uint8 colour); + /* virtual */ void DrawRect(void *video, int width, int height, uint8 colour); + /* virtual */ void CopyFromBuffer(void *video, const void *src, int width, int height); + /* virtual */ void CopyToBuffer(const void *video, void *dst, int width, int height); + /* virtual */ void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch); + /* virtual */ void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y); + /* virtual */ int BufferSize(int width, int height); + /* virtual */ void PaletteAnimate(const Palette &palette); + /* virtual */ Blitter::PaletteAnimation UsePaletteAnimation(); + /* virtual */ int GetBytesPerPixel() { return 4; } + + /** + * Look up the colour in the current palette. + */ + static inline Colour LookupColourInPalette(uint index) + { + return _cur_palette.palette[index]; + } + + /** + * Compose a colour based on RGBA values and the current pixel value. + */ + static inline Colour ComposeColourRGBANoCheck(uint r, uint g, uint b, uint a, Colour current) + { + uint cr = current.r; + uint cg = current.g; + uint cb = current.b; + + /* The 256 is wrong, it should be 255, but 256 is much faster... */ + return Colour( + ((int)(r - cr) * a) / 256 + cr, + ((int)(g - cg) * a) / 256 + cg, + ((int)(b - cb) * a) / 256 + cb); + } + + /** + * Compose a colour based on RGBA values and the current pixel value. + * Handles fully transparent and solid pixels in a special (faster) way. + */ + static inline Colour ComposeColourRGBA(uint r, uint g, uint b, uint a, Colour current) + { + if (a == 0) return current; + if (a >= 255) return Colour(r, g, b); + + return ComposeColourRGBANoCheck(r, g, b, a, current); + } + + /** + * Compose a colour based on Pixel value, alpha value, and the current pixel value. + */ + static inline Colour ComposeColourPANoCheck(Colour colour, uint a, Colour current) + { + uint r = colour.r; + uint g = colour.g; + uint b = colour.b; + + return ComposeColourRGBANoCheck(r, g, b, a, current); + } + + /** + * Compose a colour based on Pixel value, alpha value, and the current pixel value. + * Handles fully transparent and solid pixels in a special (faster) way. + */ + static inline Colour ComposeColourPA(Colour colour, uint a, Colour current) + { + if (a == 0) return current; + if (a >= 255) { + colour.a = 255; + return colour; + } + + return ComposeColourPANoCheck(colour, a, current); + } + + /** + * Make a pixel looks like it is transparent. + * @param colour the colour already on the screen. + * @param nom the amount of transparency, nominator, makes colour lighter. + * @param denom denominator, makes colour darker. + * @return the new colour for the screen. + */ + static inline Colour MakeTransparent(Colour colour, uint nom, uint denom = 256) + { + uint r = colour.r; + uint g = colour.g; + uint b = colour.b; + + return Colour(r * nom / denom, g * nom / denom, b * nom / denom); + } + + /** + * Make a colour dark grey, for specialized 32bpp remapping. + * @param r red component + * @param g green component + * @param b blue component + * @return the brightness value of the new colour, now dark grey. + */ + static inline uint8 MakeDark(uint8 r, uint8 g, uint8 b) + { + /* Magic-numbers are ~66% of those used in MakeGrey() */ + return ((r * 13063) + (g * 25647) + (b * 4981)) / 65536; + } + + /** + * Make a colour grey - based. + * @param colour the colour to make grey. + * @return the new colour, now grey. + */ + static inline Colour MakeGrey(Colour colour) + { + uint r = colour.r; + uint g = colour.g; + uint b = colour.b; + + /* To avoid doubles and stuff, multiple it with a total of 65536 (16bits), then + * divide by it to normalize the value to a byte again. See heightmap.cpp for + * information about the formula. */ + uint grey = ((r * 19595) + (g * 38470) + (b * 7471)) / 65536; + + return Colour(grey, grey, grey); + } + + static const int DEFAULT_BRIGHTNESS = 128; + + static inline Colour AdjustBrightness(Colour colour, uint8 brightness) + { + /* Shortcut for normal brightness */ + if (brightness == DEFAULT_BRIGHTNESS) return colour; + + uint16 ob = 0; + uint16 r = colour.r * brightness / DEFAULT_BRIGHTNESS; + uint16 g = colour.g * brightness / DEFAULT_BRIGHTNESS; + uint16 b = colour.b * brightness / DEFAULT_BRIGHTNESS; + + /* Sum overbright */ + if (r > 255) ob += r - 255; + if (g > 255) ob += g - 255; + if (b > 255) ob += b - 255; + + if (ob == 0) return Colour(r, g, b, colour.a); + + /* Reduce overbright strength */ + ob /= 2; + return Colour( + r >= 255 ? 255 : min(r + ob * (255 - r) / 256, 255), + g >= 255 ? 255 : min(g + ob * (255 - g) / 256, 255), + b >= 255 ? 255 : min(b + ob * (255 - b) / 256, 255), + colour.a); + } +}; + +#endif /* BLITTER_32BPP_BASE_HPP */ diff --git a/src/blitter/32bpp_optimized.cpp b/src/blitter/32bpp_optimized.cpp new file mode 100644 index 0000000..cc056f5 --- /dev/null +++ b/src/blitter/32bpp_optimized.cpp @@ -0,0 +1,401 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file 32bpp_optimized.cpp Implementation of the optimized 32 bpp blitter. */ + +#include "../stdafx.h" +#include "../zoom_func.h" +#include "../settings_type.h" +#include "32bpp_optimized.hpp" + +#include "../safeguards.h" + +/** Instantiation of the optimized 32bpp blitter factory. */ +static FBlitter_32bppOptimized iFBlitter_32bppOptimized; + +/** + * Draws a sprite to a (screen) buffer. It is templated to allow faster operation. + * + * @tparam mode blitter mode + * @param bp further blitting parameters + * @param zoom zoom level at which we are drawing + */ +template +inline void Blitter_32bppOptimized::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom) +{ + const SpriteData *src = (const SpriteData *)bp->sprite; + + /* src_px : each line begins with uint32 n = 'number of bytes in this line', + * then n times is the Colour struct for this line */ + const Colour *src_px = (const Colour *)(src->data + src->offset[zoom][0]); + /* src_n : each line begins with uint32 n = 'number of bytes in this line', + * then interleaved stream of 'm' and 'n' channels. 'm' is remap, + * 'n' is number of bytes with the same alpha channel class */ + const uint16 *src_n = (const uint16 *)(src->data + src->offset[zoom][1]); + + /* skip upper lines in src_px and src_n */ + for (uint i = bp->skip_top; i != 0; i--) { + src_px = (const Colour *)((const byte *)src_px + *(const uint32 *)src_px); + src_n = (const uint16 *)((const byte *)src_n + *(const uint32 *)src_n); + } + + /* skip lines in dst */ + Colour *dst = (Colour *)bp->dst + bp->top * bp->pitch + bp->left; + + /* store so we don't have to access it via bp everytime (compiler assumes pointer aliasing) */ + const byte *remap = bp->remap; + + for (int y = 0; y < bp->height; y++) { + /* next dst line begins here */ + Colour *dst_ln = dst + bp->pitch; + + /* next src line begins here */ + const Colour *src_px_ln = (const Colour *)((const byte *)src_px + *(const uint32 *)src_px); + src_px++; + + /* next src_n line begins here */ + const uint16 *src_n_ln = (const uint16 *)((const byte *)src_n + *(const uint32 *)src_n); + src_n += 2; + + /* we will end this line when we reach this point */ + Colour *dst_end = dst + bp->skip_left; + + /* number of pixels with the same aplha channel class */ + uint n; + + while (dst < dst_end) { + n = *src_n++; + + if (src_px->a == 0) { + dst += n; + src_px ++; + src_n++; + } else { + if (dst + n > dst_end) { + uint d = dst_end - dst; + src_px += d; + src_n += d; + + dst = dst_end - bp->skip_left; + dst_end = dst + bp->width; + + n = min(n - d, (uint)bp->width); + goto draw; + } + dst += n; + src_px += n; + src_n += n; + } + } + + dst -= bp->skip_left; + dst_end -= bp->skip_left; + + dst_end += bp->width; + + while (dst < dst_end) { + n = min(*src_n++, (uint)(dst_end - dst)); + + if (src_px->a == 0) { + dst += n; + src_px++; + src_n++; + continue; + } + + draw:; + + switch (mode) { + case BM_COLOUR_REMAP: + if (src_px->a == 255) { + do { + uint m = *src_n; + /* In case the m-channel is zero, do not remap this pixel in any way */ + if (m == 0) { + *dst = src_px->data; + } else { + uint r = remap[GB(m, 0, 8)]; + if (r != 0) *dst = this->AdjustBrightness(this->LookupColourInPalette(r), GB(m, 8, 8)); + } + dst++; + src_px++; + src_n++; + } while (--n != 0); + } else { + do { + uint m = *src_n; + if (m == 0) { + *dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst); + } else { + uint r = remap[GB(m, 0, 8)]; + if (r != 0) *dst = ComposeColourPANoCheck(this->AdjustBrightness(this->LookupColourInPalette(r), GB(m, 8, 8)), src_px->a, *dst); + } + dst++; + src_px++; + src_n++; + } while (--n != 0); + } + break; + + case BM_CRASH_REMAP: + if (src_px->a == 255) { + do { + uint m = *src_n; + if (m == 0) { + uint8 g = MakeDark(src_px->r, src_px->g, src_px->b); + *dst = ComposeColourRGBA(g, g, g, src_px->a, *dst); + } else { + uint r = remap[GB(m, 0, 8)]; + if (r != 0) *dst = this->AdjustBrightness(this->LookupColourInPalette(r), GB(m, 8, 8)); + } + dst++; + src_px++; + src_n++; + } while (--n != 0); + } else { + do { + uint m = *src_n; + if (m == 0) { + if (src_px->a != 0) { + uint8 g = MakeDark(src_px->r, src_px->g, src_px->b); + *dst = ComposeColourRGBA(g, g, g, src_px->a, *dst); + } + } else { + uint r = remap[GB(m, 0, 8)]; + if (r != 0) *dst = ComposeColourPANoCheck(this->AdjustBrightness(this->LookupColourInPalette(r), GB(m, 8, 8)), src_px->a, *dst); + } + dst++; + src_px++; + src_n++; + } while (--n != 0); + } + break; + + case BM_BLACK_REMAP: + do { + *dst = Colour(0, 0, 0); + dst++; + src_px++; + src_n++; + } while (--n != 0); + break; + + case BM_TRANSPARENT: + /* TODO -- We make an assumption here that the remap in fact is transparency, not some colour. + * This is never a problem with the code we produce, but newgrfs can make it fail... or at least: + * we produce a result the newgrf maker didn't expect ;) */ + + /* Make the current colour a bit more black, so it looks like this image is transparent */ + src_n += n; + if (src_px->a == 255) { + src_px += n; + do { + *dst = MakeTransparent(*dst, 3, 4); + dst++; + } while (--n != 0); + } else { + do { + *dst = MakeTransparent(*dst, (256 * 4 - src_px->a), 256 * 4); + dst++; + src_px++; + } while (--n != 0); + } + break; + + default: + if (src_px->a == 255) { + /* faster than memcpy(), n is usually low */ + src_n += n; + do { + *dst = src_px->data; + dst++; + src_px++; + } while (--n != 0); + } else { + src_n += n; + do { + *dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst); + dst++; + src_px++; + } while (--n != 0); + } + break; + } + } + + dst = dst_ln; + src_px = src_px_ln; + src_n = src_n_ln; + } +} + +/** + * Draws a sprite to a (screen) buffer. Calls adequate templated function. + * + * @param bp further blitting parameters + * @param mode blitter mode + * @param zoom zoom level at which we are drawing + */ +void Blitter_32bppOptimized::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) +{ + switch (mode) { + default: NOT_REACHED(); + case BM_NORMAL: Draw (bp, zoom); return; + case BM_COLOUR_REMAP: Draw(bp, zoom); return; + case BM_TRANSPARENT: Draw (bp, zoom); return; + case BM_CRASH_REMAP: Draw (bp, zoom); return; + case BM_BLACK_REMAP: Draw (bp, zoom); return; + } +} + +Sprite *Blitter_32bppOptimized::Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) +{ + /* streams of pixels (a, r, g, b channels) + * + * stored in separated stream so data are always aligned on 4B boundary */ + Colour *dst_px_orig[ZOOM_LVL_COUNT]; + + /* interleaved stream of 'm' channel and 'n' channel + * 'n' is number of following pixels with the same alpha channel class + * there are 3 classes: 0, 255, others + * + * it has to be stored in one stream so fewer registers are used - + * x86 has problems with register allocation even with this solution */ + uint16 *dst_n_orig[ZOOM_LVL_COUNT]; + + /* lengths of streams */ + uint32 lengths[ZOOM_LVL_COUNT][2]; + + ZoomLevel zoom_min; + ZoomLevel zoom_max; + + if (sprite->type == ST_FONT) { + zoom_min = ZOOM_LVL_NORMAL; + zoom_max = ZOOM_LVL_NORMAL; + } else { + zoom_min = _settings_client.gui.zoom_min; + zoom_max = _settings_client.gui.zoom_max; + if (zoom_max == zoom_min) zoom_max = ZOOM_LVL_MAX; + } + + for (ZoomLevel z = zoom_min; z <= zoom_max; z++) { + const SpriteLoader::Sprite *src_orig = &sprite[z]; + + uint size = src_orig->height * src_orig->width; + + dst_px_orig[z] = CallocT(size + src_orig->height * 2); + dst_n_orig[z] = CallocT(size * 2 + src_orig->height * 4 * 2); + + uint32 *dst_px_ln = (uint32 *)dst_px_orig[z]; + uint32 *dst_n_ln = (uint32 *)dst_n_orig[z]; + + const SpriteLoader::CommonPixel *src = (const SpriteLoader::CommonPixel *)src_orig->data; + + for (uint y = src_orig->height; y > 0; y--) { + Colour *dst_px = (Colour *)(dst_px_ln + 1); + uint16 *dst_n = (uint16 *)(dst_n_ln + 1); + + uint16 *dst_len = dst_n++; + + uint last = 3; + int len = 0; + + for (uint x = src_orig->width; x > 0; x--) { + uint8 a = src->a; + uint t = a > 0 && a < 255 ? 1 : a; + + if (last != t || len == 65535) { + if (last != 3) { + *dst_len = len; + dst_len = dst_n++; + } + len = 0; + } + + last = t; + len++; + + if (a != 0) { + dst_px->a = a; + *dst_n = src->m; + if (src->m != 0) { + /* Get brightest value */ + uint8 rgb_max = max(src->r, max(src->g, src->b)); + + /* Black pixel (8bpp or old 32bpp image), so use default value */ + if (rgb_max == 0) rgb_max = DEFAULT_BRIGHTNESS; + *dst_n |= rgb_max << 8; + + /* Pre-convert the mapping channel to a RGB value */ + Colour colour = this->AdjustBrightness(this->LookupColourInPalette(src->m), rgb_max); + dst_px->r = colour.r; + dst_px->g = colour.g; + dst_px->b = colour.b; + } else { + dst_px->r = src->r; + dst_px->g = src->g; + dst_px->b = src->b; + } + dst_px++; + dst_n++; + } else if (len == 1) { + dst_px++; + *dst_n = src->m; + dst_n++; + } + + src++; + } + + if (last != 3) { + *dst_len = len; + } + + dst_px = (Colour *)AlignPtr(dst_px, 4); + dst_n = (uint16 *)AlignPtr(dst_n, 4); + + *dst_px_ln = (uint8 *)dst_px - (uint8 *)dst_px_ln; + *dst_n_ln = (uint8 *)dst_n - (uint8 *)dst_n_ln; + + dst_px_ln = (uint32 *)dst_px; + dst_n_ln = (uint32 *)dst_n; + } + + lengths[z][0] = (byte *)dst_px_ln - (byte *)dst_px_orig[z]; // all are aligned to 4B boundary + lengths[z][1] = (byte *)dst_n_ln - (byte *)dst_n_orig[z]; + } + + uint len = 0; // total length of data + for (ZoomLevel z = zoom_min; z <= zoom_max; z++) { + len += lengths[z][0] + lengths[z][1]; + } + + Sprite *dest_sprite = (Sprite *)allocator(sizeof(*dest_sprite) + sizeof(SpriteData) + len); + + dest_sprite->height = sprite->height; + dest_sprite->width = sprite->width; + dest_sprite->x_offs = sprite->x_offs; + dest_sprite->y_offs = sprite->y_offs; + + SpriteData *dst = (SpriteData *)dest_sprite->data; + memset(dst, 0, sizeof(*dst)); + + for (ZoomLevel z = zoom_min; z <= zoom_max; z++) { + dst->offset[z][0] = z == zoom_min ? 0 : lengths[z - 1][1] + dst->offset[z - 1][1]; + dst->offset[z][1] = lengths[z][0] + dst->offset[z][0]; + + memcpy(dst->data + dst->offset[z][0], dst_px_orig[z], lengths[z][0]); + memcpy(dst->data + dst->offset[z][1], dst_n_orig[z], lengths[z][1]); + + free(dst_px_orig[z]); + free(dst_n_orig[z]); + } + + return dest_sprite; +} diff --git a/src/blitter/32bpp_optimized.hpp b/src/blitter/32bpp_optimized.hpp new file mode 100644 index 0000000..c261aa3 --- /dev/null +++ b/src/blitter/32bpp_optimized.hpp @@ -0,0 +1,41 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file 32bpp_optimized.hpp Optimized 32 bpp blitter. */ + +#ifndef BLITTER_32BPP_OPTIMIZED_HPP +#define BLITTER_32BPP_OPTIMIZED_HPP + +#include "32bpp_simple.hpp" + +/** The optimised 32 bpp blitter (without palette animation). */ +class Blitter_32bppOptimized : public Blitter_32bppSimple { +public: + /** Data stored about a (single) sprite. */ + struct SpriteData { + uint32 offset[ZOOM_LVL_COUNT][2]; ///< Offsets (from .data) to streams for different zoom levels, and the normal and remap image information. + byte data[]; ///< Data, all zoomlevels. + }; + + /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); + /* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator); + + /* virtual */ const char *GetName() { return "32bpp-optimized"; } + + template void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom); +}; + +/** Factory for the optimised 32 bpp blitter (without palette animation). */ +class FBlitter_32bppOptimized : public BlitterFactory { +public: + FBlitter_32bppOptimized() : BlitterFactory("32bpp-optimized", "32bpp Optimized Blitter (no palette animation)") {} + /* virtual */ Blitter *CreateInstance() { return new Blitter_32bppOptimized(); } +}; + +#endif /* BLITTER_32BPP_OPTIMIZED_HPP */ diff --git a/src/blitter/32bpp_simple.cpp b/src/blitter/32bpp_simple.cpp new file mode 100644 index 0000000..92375be --- /dev/null +++ b/src/blitter/32bpp_simple.cpp @@ -0,0 +1,155 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file 32bpp_simple.cpp Implementation of the simple 32 bpp blitter. */ + +#include "../stdafx.h" +#include "../zoom_func.h" +#include "32bpp_simple.hpp" + +#include "../table/sprites.h" + +#include "../safeguards.h" + +/** Instantiation of the simple 32bpp blitter factory. */ +static FBlitter_32bppSimple iFBlitter_32bppSimple; + +void Blitter_32bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) +{ + const Blitter_32bppSimple::Pixel *src, *src_line; + Colour *dst, *dst_line; + + /* Find where to start reading in the source sprite */ + src_line = (const Blitter_32bppSimple::Pixel *)bp->sprite + (bp->skip_top * bp->sprite_width + bp->skip_left) * ScaleByZoom(1, zoom); + dst_line = (Colour *)bp->dst + bp->top * bp->pitch + bp->left; + + for (int y = 0; y < bp->height; y++) { + dst = dst_line; + dst_line += bp->pitch; + + src = src_line; + src_line += bp->sprite_width * ScaleByZoom(1, zoom); + + for (int x = 0; x < bp->width; x++) { + switch (mode) { + case BM_COLOUR_REMAP: + /* In case the m-channel is zero, do not remap this pixel in any way */ + if (src->m == 0) { + if (src->a != 0) *dst = ComposeColourRGBA(src->r, src->g, src->b, src->a, *dst); + } else { + if (bp->remap[src->m] != 0) *dst = ComposeColourPA(this->AdjustBrightness(this->LookupColourInPalette(bp->remap[src->m]), src->v), src->a, *dst); + } + break; + + case BM_CRASH_REMAP: + if (src->m == 0) { + if (src->a != 0) { + uint8 g = MakeDark(src->r, src->g, src->b); + *dst = ComposeColourRGBA(g, g, g, src->a, *dst); + } + } else { + if (bp->remap[src->m] != 0) *dst = ComposeColourPA(this->AdjustBrightness(this->LookupColourInPalette(bp->remap[src->m]), src->v), src->a, *dst); + } + break; + + case BM_BLACK_REMAP: + if (src->a != 0) { + *dst = Colour(0, 0, 0); + } + break; + + case BM_TRANSPARENT: + /* TODO -- We make an assumption here that the remap in fact is transparency, not some colour. + * This is never a problem with the code we produce, but newgrfs can make it fail... or at least: + * we produce a result the newgrf maker didn't expect ;) */ + + /* Make the current colour a bit more black, so it looks like this image is transparent */ + if (src->a != 0) *dst = MakeTransparent(*dst, 192); + break; + + default: + if (src->a != 0) *dst = ComposeColourRGBA(src->r, src->g, src->b, src->a, *dst); + break; + } + dst++; + src += ScaleByZoom(1, zoom); + } + } +} + +void Blitter_32bppSimple::DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) +{ + Colour *udst = (Colour *)dst; + + if (pal == PALETTE_TO_TRANSPARENT) { + do { + for (int i = 0; i != width; i++) { + *udst = MakeTransparent(*udst, 154); + udst++; + } + udst = udst - width + _screen.pitch; + } while (--height); + return; + } + if (pal == PALETTE_NEWSPAPER) { + do { + for (int i = 0; i != width; i++) { + *udst = MakeGrey(*udst); + udst++; + } + udst = udst - width + _screen.pitch; + } while (--height); + return; + } + + DEBUG(misc, 0, "32bpp blitter doesn't know how to draw this colour table ('%d')", pal); +} + +Sprite *Blitter_32bppSimple::Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) +{ + Blitter_32bppSimple::Pixel *dst; + Sprite *dest_sprite = (Sprite *)allocator(sizeof(*dest_sprite) + (size_t)sprite->height * (size_t)sprite->width * sizeof(*dst)); + + dest_sprite->height = sprite->height; + dest_sprite->width = sprite->width; + dest_sprite->x_offs = sprite->x_offs; + dest_sprite->y_offs = sprite->y_offs; + + dst = (Blitter_32bppSimple::Pixel *)dest_sprite->data; + SpriteLoader::CommonPixel *src = (SpriteLoader::CommonPixel *)sprite->data; + + for (int i = 0; i < sprite->height * sprite->width; i++) { + if (src->m == 0) { + dst[i].r = src->r; + dst[i].g = src->g; + dst[i].b = src->b; + dst[i].a = src->a; + dst[i].m = 0; + dst[i].v = 0; + } else { + /* Get brightest value */ + uint8 rgb_max = max(src->r, max(src->g, src->b)); + + /* Black pixel (8bpp or old 32bpp image), so use default value */ + if (rgb_max == 0) rgb_max = DEFAULT_BRIGHTNESS; + dst[i].v = rgb_max; + + /* Pre-convert the mapping channel to a RGB value */ + Colour colour = this->AdjustBrightness(this->LookupColourInPalette(src->m), dst[i].v); + dst[i].r = colour.r; + dst[i].g = colour.g; + dst[i].b = colour.b; + dst[i].a = src->a; + dst[i].m = src->m; + } + src++; + } + + return dest_sprite; +} diff --git a/src/blitter/32bpp_simple.hpp b/src/blitter/32bpp_simple.hpp new file mode 100644 index 0000000..0751f6f --- /dev/null +++ b/src/blitter/32bpp_simple.hpp @@ -0,0 +1,43 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file 32bpp_simple.hpp Simple 32 bpp blitter. */ + +#ifndef BLITTER_32BPP_SIMPLE_HPP +#define BLITTER_32BPP_SIMPLE_HPP + +#include "32bpp_base.hpp" +#include "factory.hpp" + +/** The most trivial 32 bpp blitter (without palette animation). */ +class Blitter_32bppSimple : public Blitter_32bppBase { + struct Pixel { + uint8 r; ///< Red-channel + uint8 g; ///< Green-channel + uint8 b; ///< Blue-channel + uint8 a; ///< Alpha-channel + uint8 m; ///< Remap-channel + uint8 v; ///< Brightness-channel + }; +public: + /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); + /* virtual */ void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal); + /* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator); + + /* virtual */ const char *GetName() { return "32bpp-simple"; } +}; + +/** Factory for the simple 32 bpp blitter. */ +class FBlitter_32bppSimple : public BlitterFactory { +public: + FBlitter_32bppSimple() : BlitterFactory("32bpp-simple", "32bpp Simple Blitter (no palette animation)") {} + /* virtual */ Blitter *CreateInstance() { return new Blitter_32bppSimple(); } +}; + +#endif /* BLITTER_32BPP_SIMPLE_HPP */ diff --git a/src/blitter/32bpp_sse2.cpp b/src/blitter/32bpp_sse2.cpp new file mode 100644 index 0000000..ae2b3cc --- /dev/null +++ b/src/blitter/32bpp_sse2.cpp @@ -0,0 +1,143 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file 32bpp_sse2.cpp Implementation of the SSE2 32 bpp blitter. */ + +#ifdef WITH_SSE + +#include "../stdafx.h" +#include "../zoom_func.h" +#include "../settings_type.h" +#include "32bpp_sse2.hpp" +#include "32bpp_sse_func.hpp" + +#include "../safeguards.h" + +/** Instantiation of the SSE2 32bpp blitter factory. */ +static FBlitter_32bppSSE2 iFBlitter_32bppSSE2; + +Sprite *Blitter_32bppSSE_Base::Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) +{ + /* First uint32 of a line = the number of transparent pixels from the left. + * Second uint32 of a line = the number of transparent pixels from the right. + * Then all RGBA then all MV. + */ + ZoomLevel zoom_min = ZOOM_LVL_NORMAL; + ZoomLevel zoom_max = ZOOM_LVL_NORMAL; + if (sprite->type != ST_FONT) { + zoom_min = _settings_client.gui.zoom_min; + zoom_max = _settings_client.gui.zoom_max; + if (zoom_max == zoom_min) zoom_max = ZOOM_LVL_MAX; + } + + /* Calculate sizes and allocate. */ + SpriteData sd; + memset(&sd, 0, sizeof(sd)); + uint all_sprites_size = 0; + for (ZoomLevel z = zoom_min; z <= zoom_max; z++) { + const SpriteLoader::Sprite *src_sprite = &sprite[z]; + sd.infos[z].sprite_width = src_sprite->width; + sd.infos[z].sprite_offset = all_sprites_size; + sd.infos[z].sprite_line_size = sizeof(Colour) * src_sprite->width + sizeof(uint32) * META_LENGTH; + + const uint rgba_size = sd.infos[z].sprite_line_size * src_sprite->height; + sd.infos[z].mv_offset = all_sprites_size + rgba_size; + + const uint mv_size = sizeof(MapValue) * src_sprite->width * src_sprite->height; + all_sprites_size += rgba_size + mv_size; + } + + Sprite *dst_sprite = (Sprite *) allocator(sizeof(Sprite) + sizeof(SpriteData) + all_sprites_size); + dst_sprite->height = sprite->height; + dst_sprite->width = sprite->width; + dst_sprite->x_offs = sprite->x_offs; + dst_sprite->y_offs = sprite->y_offs; + memcpy(dst_sprite->data, &sd, sizeof(SpriteData)); + + /* Copy colours and determine flags. */ + bool has_remap = false; + bool has_anim = false; + bool has_translucency = false; + for (ZoomLevel z = zoom_min; z <= zoom_max; z++) { + const SpriteLoader::Sprite *src_sprite = &sprite[z]; + const SpriteLoader::CommonPixel *src = (const SpriteLoader::CommonPixel *) src_sprite->data; + Colour *dst_rgba_line = (Colour *) &dst_sprite->data[sizeof(SpriteData) + sd.infos[z].sprite_offset]; + MapValue *dst_mv = (MapValue *) &dst_sprite->data[sizeof(SpriteData) + sd.infos[z].mv_offset]; + for (uint y = src_sprite->height; y != 0; y--) { + Colour *dst_rgba = dst_rgba_line + META_LENGTH; + for (uint x = src_sprite->width; x != 0; x--) { + if (src->a != 0) { + dst_rgba->a = src->a; + if (src->a != 0 && src->a != 255) has_translucency = true; + dst_mv->m = src->m; + if (src->m != 0) { + /* Do some accounting for flags. */ + has_remap = true; + if (src->m >= PALETTE_ANIM_START) has_anim = true; + + /* Get brightest value (or default brightness if it's a black pixel). */ + const uint8 rgb_max = max(src->r, max(src->g, src->b)); + dst_mv->v = (rgb_max == 0) ? Blitter_32bppBase::DEFAULT_BRIGHTNESS : rgb_max; + + /* Pre-convert the mapping channel to a RGB value. */ + const Colour colour = AdjustBrightneSSE(Blitter_32bppBase::LookupColourInPalette(src->m), dst_mv->v); + dst_rgba->r = colour.r; + dst_rgba->g = colour.g; + dst_rgba->b = colour.b; + } else { + dst_rgba->r = src->r; + dst_rgba->g = src->g; + dst_rgba->b = src->b; + dst_mv->v = Blitter_32bppBase::DEFAULT_BRIGHTNESS; + } + } else { + dst_rgba->data = 0; + *(uint16*) dst_mv = 0; + } + dst_rgba++; + dst_mv++; + src++; + } + + /* Count the number of transparent pixels from the left. */ + dst_rgba = dst_rgba_line + META_LENGTH; + uint32 nb_pix_transp = 0; + for (uint x = src_sprite->width; x != 0; x--) { + if (dst_rgba->a == 0) nb_pix_transp++; + else break; + dst_rgba++; + } + (*dst_rgba_line).data = nb_pix_transp; + + Colour *nb_right = dst_rgba_line + 1; + dst_rgba_line = (Colour*) ((byte*) dst_rgba_line + sd.infos[z].sprite_line_size); + + /* Count the number of transparent pixels from the right. */ + dst_rgba = dst_rgba_line - 1; + nb_pix_transp = 0; + for (uint x = src_sprite->width; x != 0; x--) { + if (dst_rgba->a == 0) nb_pix_transp++; + else break; + dst_rgba--; + } + (*nb_right).data = nb_pix_transp; + } + } + + /* Store sprite flags. */ + sd.flags = SF_NONE; + if (has_translucency) sd.flags |= SF_TRANSLUCENT; + if (!has_remap) sd.flags |= SF_NO_REMAP; + if (!has_anim) sd.flags |= SF_NO_ANIM; + memcpy(dst_sprite->data, &sd, sizeof(SpriteData)); + + return dst_sprite; +} + +#endif /* WITH_SSE */ diff --git a/src/blitter/32bpp_sse2.hpp b/src/blitter/32bpp_sse2.hpp new file mode 100644 index 0000000..d6b17f6 --- /dev/null +++ b/src/blitter/32bpp_sse2.hpp @@ -0,0 +1,104 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file 32bpp_sse2.hpp SSE2 32 bpp blitter. */ + +#ifndef BLITTER_32BPP_SSE2_HPP +#define BLITTER_32BPP_SSE2_HPP + +#ifdef WITH_SSE + +#ifndef SSE_VERSION +#define SSE_VERSION 2 +#endif + +#ifndef FULL_ANIMATION +#define FULL_ANIMATION 0 +#endif + +#include "32bpp_sse_type.h" + +/** Base methods for 32bpp SSE blitters. */ +class Blitter_32bppSSE_Base { +public: + virtual ~Blitter_32bppSSE_Base() {} + + struct MapValue { + uint8 m; + uint8 v; + }; + assert_compile(sizeof(MapValue) == 2); + + /** Helper for creating specialised functions for specific optimisations. */ + enum ReadMode { + RM_WITH_SKIP, ///< Use normal code for skipping empty pixels. + RM_WITH_MARGIN, ///< Use cached number of empty pixels at begin and end of line to reduce work. + RM_NONE, ///< No specialisation. + }; + + /** Helper for creating specialised functions for the case where the sprite width is odd or even. */ + enum BlockType { + BT_EVEN, ///< An even number of pixels in the width; no need for a special case for the last pixel. + BT_ODD, ///< An odd number of pixels in the width; special case for the last pixel. + BT_NONE, ///< No specialisation for either case. + }; + + /** Helper for using specialised functions designed to prevent whenever it's possible things like: + * - IO (reading video buffer), + * - calculations (alpha blending), + * - heavy branching (remap lookups and animation buffer handling). + */ + enum SpriteFlags { + SF_NONE = 0, + SF_TRANSLUCENT = 1 << 1, ///< The sprite has at least 1 translucent pixel. + SF_NO_REMAP = 1 << 2, ///< The sprite has no remappable colour pixel. + SF_NO_ANIM = 1 << 3, ///< The sprite has no palette animated pixel. + }; + + /** Data stored about a (single) sprite. */ + struct SpriteInfo { + uint32 sprite_offset; ///< The offset to the sprite data. + uint32 mv_offset; ///< The offset to the map value data. + uint16 sprite_line_size; ///< The size of a single line (pitch). + uint16 sprite_width; ///< The width of the sprite. + }; + struct SpriteData { + SpriteFlags flags; + SpriteInfo infos[ZOOM_LVL_COUNT]; + byte data[]; ///< Data, all zoomlevels. + }; + + Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator); +}; + +DECLARE_ENUM_AS_BIT_SET(Blitter_32bppSSE_Base::SpriteFlags); + +/** The SSE2 32 bpp blitter (without palette animation). */ +class Blitter_32bppSSE2 : public Blitter_32bppSimple, public Blitter_32bppSSE_Base { +public: + /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); + template + void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom); + + /* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) { + return Blitter_32bppSSE_Base::Encode(sprite, allocator); + } + + /* virtual */ const char *GetName() { return "32bpp-sse2"; } +}; + +/** Factory for the SSE2 32 bpp blitter (without palette animation). */ +class FBlitter_32bppSSE2 : public BlitterFactory { +public: + FBlitter_32bppSSE2() : BlitterFactory("32bpp-sse2", "32bpp SSE2 Blitter (no palette animation)", HasCPUIDFlag(1, 3, 26)) {} + /* virtual */ Blitter *CreateInstance() { return new Blitter_32bppSSE2(); } +}; + +#endif /* WITH_SSE */ +#endif /* BLITTER_32BPP_SSE2_HPP */ diff --git a/src/blitter/32bpp_sse4.cpp b/src/blitter/32bpp_sse4.cpp new file mode 100644 index 0000000..723264f --- /dev/null +++ b/src/blitter/32bpp_sse4.cpp @@ -0,0 +1,25 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file 32bpp_sse4.cpp Implementation of the SSE4 32 bpp blitter. */ + +#ifdef WITH_SSE + +#include "../stdafx.h" +#include "../zoom_func.h" +#include "../settings_type.h" +#include "32bpp_sse4.hpp" +#include "32bpp_sse_func.hpp" + +#include "../safeguards.h" + +/** Instantiation of the SSE4 32bpp blitter factory. */ +static FBlitter_32bppSSE4 iFBlitter_32bppSSE4; + +#endif /* WITH_SSE */ diff --git a/src/blitter/32bpp_sse4.hpp b/src/blitter/32bpp_sse4.hpp new file mode 100644 index 0000000..9c59d25 --- /dev/null +++ b/src/blitter/32bpp_sse4.hpp @@ -0,0 +1,44 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file 32bpp_sse4.hpp SSE4 32 bpp blitter. */ + +#ifndef BLITTER_32BPP_SSE4_HPP +#define BLITTER_32BPP_SSE4_HPP + +#ifdef WITH_SSE + +#ifndef SSE_VERSION +#define SSE_VERSION 4 +#endif + +#ifndef FULL_ANIMATION +#define FULL_ANIMATION 0 +#endif + +#include "32bpp_ssse3.hpp" + +/** The SSE4 32 bpp blitter (without palette animation). */ +class Blitter_32bppSSE4 : public Blitter_32bppSSSE3 { +public: + /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); + template + void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom); + /* virtual */ const char *GetName() { return "32bpp-sse4"; } +}; + +/** Factory for the SSE4 32 bpp blitter (without palette animation). */ +class FBlitter_32bppSSE4: public BlitterFactory { +public: + FBlitter_32bppSSE4() : BlitterFactory("32bpp-sse4", "32bpp SSE4 Blitter (no palette animation)", HasCPUIDFlag(1, 2, 19)) {} + /* virtual */ Blitter *CreateInstance() { return new Blitter_32bppSSE4(); } +}; + +#endif /* WITH_SSE */ +#endif /* BLITTER_32BPP_SSE4_HPP */ diff --git a/src/blitter/32bpp_sse_func.hpp b/src/blitter/32bpp_sse_func.hpp new file mode 100644 index 0000000..fb0ce9e --- /dev/null +++ b/src/blitter/32bpp_sse_func.hpp @@ -0,0 +1,467 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file 32bpp_sse_func.hpp Functions related to SSE 32 bpp blitter. */ + +#ifndef BLITTER_32BPP_SSE_FUNC_HPP +#define BLITTER_32BPP_SSE_FUNC_HPP + +#ifdef WITH_SSE + +static inline void InsertFirstUint32(const uint32 value, __m128i &into) +{ +#if (SSE_VERSION >= 4) + into = _mm_insert_epi32(into, value, 0); +#else + into = _mm_insert_epi16(into, value, 0); + into = _mm_insert_epi16(into, value >> 16, 1); +#endif +} + +static inline void InsertSecondUint32(const uint32 value, __m128i &into) +{ +#if (SSE_VERSION >= 4) + into = _mm_insert_epi32(into, value, 1); +#else + into = _mm_insert_epi16(into, value, 2); + into = _mm_insert_epi16(into, value >> 16, 3); +#endif +} + +static inline void LoadUint64(const uint64 value, __m128i &into) +{ +#ifdef _SQ64 + into = _mm_cvtsi64_si128(value); +#else + #if (SSE_VERSION >= 4) + into = _mm_cvtsi32_si128(value); + InsertSecondUint32(value >> 32, into); + #else + (*(um128i*) &into).m128i_u64[0] = value; + #endif +#endif +} + +static inline __m128i PackUnsaturated(__m128i from, const __m128i &mask) +{ +#if (SSE_VERSION == 2) + from = _mm_and_si128(from, mask); // PAND, wipe high bytes to keep low bytes when packing + return _mm_packus_epi16(from, from); // PACKUSWB, pack 2 colours (with saturation) +#else + return _mm_shuffle_epi8(from, mask); +#endif +} + +static inline __m128i DistributeAlpha(const __m128i from, const __m128i &mask) +{ +#if (SSE_VERSION == 2) + __m128i alphaAB = _mm_shufflelo_epi16(from, 0x3F); // PSHUFLW, put alpha1 in front of each rgb1 + return _mm_shufflehi_epi16(alphaAB, 0x3F); // PSHUFHW, put alpha2 in front of each rgb2 +#else + return _mm_shuffle_epi8(from, mask); +#endif +} + +static inline __m128i AlphaBlendTwoPixels(__m128i src, __m128i dst, const __m128i &distribution_mask, const __m128i &pack_mask) +{ + __m128i srcAB = _mm_unpacklo_epi8(src, _mm_setzero_si128()); // PUNPCKLBW, expand each uint8 into uint16 + __m128i dstAB = _mm_unpacklo_epi8(dst, _mm_setzero_si128()); + + __m128i alphaAB = _mm_cmpgt_epi16(srcAB, _mm_setzero_si128()); // PCMPGTW, if (alpha > 0) a++; + alphaAB = _mm_srli_epi16(alphaAB, 15); + alphaAB = _mm_add_epi16(alphaAB, srcAB); + alphaAB = DistributeAlpha(alphaAB, distribution_mask); + + srcAB = _mm_sub_epi16(srcAB, dstAB); // PSUBW, (r - Cr) + srcAB = _mm_mullo_epi16(srcAB, alphaAB); // PMULLW, a*(r - Cr) + srcAB = _mm_srli_epi16(srcAB, 8); // PSRLW, a*(r - Cr)/256 + srcAB = _mm_add_epi16(srcAB, dstAB); // PADDW, a*(r - Cr)/256 + Cr + return PackUnsaturated(srcAB, pack_mask); +} + +/* Darken 2 pixels. + * rgb = rgb * ((256/4) * 4 - (alpha/4)) / ((256/4) * 4) + */ +static inline __m128i DarkenTwoPixels(__m128i src, __m128i dst, const __m128i &distribution_mask, const __m128i &tr_nom_base) +{ + __m128i srcAB = _mm_unpacklo_epi8(src, _mm_setzero_si128()); + __m128i dstAB = _mm_unpacklo_epi8(dst, _mm_setzero_si128()); + __m128i alphaAB = DistributeAlpha(srcAB, distribution_mask); + alphaAB = _mm_srli_epi16(alphaAB, 2); // Reduce to 64 levels of shades so the max value fits in 16 bits. + __m128i nom = _mm_sub_epi16(tr_nom_base, alphaAB); + dstAB = _mm_mullo_epi16(dstAB, nom); + dstAB = _mm_srli_epi16(dstAB, 8); + return _mm_packus_epi16(dstAB, dstAB); +} + +IGNORE_UNINITIALIZED_WARNING_START +static Colour ReallyAdjustBrightness(Colour colour, uint8 brightness) +{ + uint64 c16 = colour.b | (uint64) colour.g << 16 | (uint64) colour.r << 32; + c16 *= brightness; + uint64 c16_ob = c16; // Helps out of order execution. + c16 /= Blitter_32bppBase::DEFAULT_BRIGHTNESS; + c16 &= 0x01FF01FF01FFULL; + + /* Sum overbright (maximum for each rgb is 508, 9 bits, -255 is changed in -256 so we just have to take the 8 lower bits into account). */ + c16_ob = (((c16_ob >> (8 + 7)) & 0x0100010001ULL) * 0xFF) & c16; + const uint ob = ((uint16) c16_ob + (uint16) (c16_ob >> 16) + (uint16) (c16_ob >> 32)) / 2; + + const uint32 alpha32 = colour.data & 0xFF000000; + __m128i ret; + LoadUint64(c16, ret); + if (ob != 0) { + __m128i ob128 = _mm_cvtsi32_si128(ob); + ob128 = _mm_shufflelo_epi16(ob128, 0xC0); + __m128i white = OVERBRIGHT_VALUE_MASK; + __m128i c128 = ret; + ret = _mm_subs_epu16(white, c128); // PSUBUSW, (255 - rgb) + ret = _mm_mullo_epi16(ret, ob128); // PMULLW, ob*(255 - rgb) + ret = _mm_srli_epi16(ret, 8); // PSRLW, ob*(255 - rgb)/256 + ret = _mm_add_epi16(ret, c128); // PADDW, ob*(255 - rgb)/256 + rgb + } + + ret = _mm_packus_epi16(ret, ret); // PACKUSWB, saturate and pack. + return alpha32 | _mm_cvtsi128_si32(ret); +} +IGNORE_UNINITIALIZED_WARNING_STOP + +/** ReallyAdjustBrightness() is not called that often. + * Inlining this function implies a far jump, which has a huge latency. + */ +static inline Colour AdjustBrightneSSE(Colour colour, uint8 brightness) +{ + /* Shortcut for normal brightness. */ + if (brightness == Blitter_32bppBase::DEFAULT_BRIGHTNESS) return colour; + + return ReallyAdjustBrightness(colour, brightness); +} + +static inline __m128i AdjustBrightnessOfTwoPixels(__m128i from, uint32 brightness) +{ +#if (SSE_VERSION < 3) + NOT_REACHED(); +#else + /* The following dataflow differs from the one of AdjustBrightness() only for alpha. + * In order to keep alpha in colAB, insert a 1 in a unused brightness byte (a*1->a). + * OK, not a 1 but DEFAULT_BRIGHTNESS to compensate the div. + */ + brightness &= 0xFF00FF00; + brightness += Blitter_32bppBase::DEFAULT_BRIGHTNESS; + + __m128i colAB = _mm_unpacklo_epi8(from, _mm_setzero_si128()); + __m128i briAB = _mm_cvtsi32_si128(brightness); + briAB = _mm_shuffle_epi8(briAB, BRIGHTNESS_LOW_CONTROL_MASK); // DEFAULT_BRIGHTNESS in 0, 0x00 in 2. + colAB = _mm_mullo_epi16(colAB, briAB); + __m128i colAB_ob = _mm_srli_epi16(colAB, 8 + 7); + colAB = _mm_srli_epi16(colAB, 7); + + /* Sum overbright. + * Maximum for each rgb is 508 => 9 bits. The highest bit tells if there is overbright. + * -255 is changed in -256 so we just have to take the 8 lower bits into account. + */ + colAB = _mm_and_si128(colAB, BRIGHTNESS_DIV_CLEANER); + colAB_ob = _mm_and_si128(colAB_ob, OVERBRIGHT_PRESENCE_MASK); + colAB_ob = _mm_mullo_epi16(colAB_ob, OVERBRIGHT_VALUE_MASK); + colAB_ob = _mm_and_si128(colAB_ob, colAB); + __m128i obAB = _mm_hadd_epi16(_mm_hadd_epi16(colAB_ob, _mm_setzero_si128()), _mm_setzero_si128()); + + obAB = _mm_srli_epi16(obAB, 1); // Reduce overbright strength. + obAB = _mm_shuffle_epi8(obAB, OVERBRIGHT_CONTROL_MASK); + __m128i retAB = OVERBRIGHT_VALUE_MASK; // ob_mask is equal to white. + retAB = _mm_subs_epu16(retAB, colAB); // (255 - rgb) + retAB = _mm_mullo_epi16(retAB, obAB); // ob*(255 - rgb) + retAB = _mm_srli_epi16(retAB, 8); // ob*(255 - rgb)/256 + retAB = _mm_add_epi16(retAB, colAB); // ob*(255 - rgb)/256 + rgb + + return _mm_packus_epi16(retAB, retAB); +#endif +} + +#if FULL_ANIMATION == 0 +/** + * Draws a sprite to a (screen) buffer. It is templated to allow faster operation. + * + * @tparam mode blitter mode + * @param bp further blitting parameters + * @param zoom zoom level at which we are drawing + */ +IGNORE_UNINITIALIZED_WARNING_START +template +#if (SSE_VERSION == 2) +inline void Blitter_32bppSSE2::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom) +#elif (SSE_VERSION == 3) +inline void Blitter_32bppSSSE3::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom) +#elif (SSE_VERSION == 4) +inline void Blitter_32bppSSE4::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom) +#endif +{ + const byte * const remap = bp->remap; + Colour *dst_line = (Colour *) bp->dst + bp->top * bp->pitch + bp->left; + int effective_width = bp->width; + + /* Find where to start reading in the source sprite. */ + const SpriteData * const sd = (const SpriteData *) bp->sprite; + const SpriteInfo * const si = &sd->infos[zoom]; + const MapValue *src_mv_line = (const MapValue *) &sd->data[si->mv_offset] + bp->skip_top * si->sprite_width; + const Colour *src_rgba_line = (const Colour *) ((const byte *) &sd->data[si->sprite_offset] + bp->skip_top * si->sprite_line_size); + + if (read_mode != RM_WITH_MARGIN) { + src_rgba_line += bp->skip_left; + src_mv_line += bp->skip_left; + } + const MapValue *src_mv = src_mv_line; + + /* Load these variables into register before loop. */ +#if (SSE_VERSION == 2) + const __m128i clear_hi = CLEAR_HIGH_BYTE_MASK; + #define ALPHA_BLEND_PARAM_1 clear_hi + #define ALPHA_BLEND_PARAM_2 clear_hi + #define DARKEN_PARAM_1 tr_nom_base + #define DARKEN_PARAM_2 tr_nom_base +#else + const __m128i a_cm = ALPHA_CONTROL_MASK; + const __m128i pack_low_cm = PACK_LOW_CONTROL_MASK; + #define ALPHA_BLEND_PARAM_1 a_cm + #define ALPHA_BLEND_PARAM_2 pack_low_cm + #define DARKEN_PARAM_1 a_cm + #define DARKEN_PARAM_2 tr_nom_base +#endif + const __m128i tr_nom_base = TRANSPARENT_NOM_BASE; + + for (int y = bp->height; y != 0; y--) { + Colour *dst = dst_line; + const Colour *src = src_rgba_line + META_LENGTH; + if (mode == BM_COLOUR_REMAP || mode == BM_CRASH_REMAP) src_mv = src_mv_line; + + if (read_mode == RM_WITH_MARGIN) { + assert(bt_last == BT_NONE); // or you must ensure block type is preserved + src += src_rgba_line[0].data; + dst += src_rgba_line[0].data; + if (mode == BM_COLOUR_REMAP || mode == BM_CRASH_REMAP) src_mv += src_rgba_line[0].data; + const int width_diff = si->sprite_width - bp->width; + effective_width = bp->width - (int) src_rgba_line[0].data; + const int delta_diff = (int) src_rgba_line[1].data - width_diff; + const int new_width = effective_width - delta_diff; + effective_width = delta_diff > 0 ? new_width : effective_width; + if (effective_width <= 0) goto next_line; + } + + switch (mode) { + default: + if (!translucent) { + for (uint x = (uint) effective_width; x > 0; x--) { + if (src->a) *dst = *src; + src++; + dst++; + } + break; + } + + for (uint x = (uint) effective_width / 2; x > 0; x--) { + __m128i srcABCD = _mm_loadl_epi64((const __m128i*) src); + __m128i dstABCD = _mm_loadl_epi64((__m128i*) dst); + _mm_storel_epi64((__m128i*) dst, AlphaBlendTwoPixels(srcABCD, dstABCD, ALPHA_BLEND_PARAM_1, ALPHA_BLEND_PARAM_2)); + src += 2; + dst += 2; + } + + if ((bt_last == BT_NONE && effective_width & 1) || bt_last == BT_ODD) { + __m128i srcABCD = _mm_cvtsi32_si128(src->data); + __m128i dstABCD = _mm_cvtsi32_si128(dst->data); + dst->data = _mm_cvtsi128_si32(AlphaBlendTwoPixels(srcABCD, dstABCD, ALPHA_BLEND_PARAM_1, ALPHA_BLEND_PARAM_2)); + } + break; + + case BM_COLOUR_REMAP: +#if (SSE_VERSION >= 3) + for (uint x = (uint) effective_width / 2; x > 0; x--) { + __m128i srcABCD = _mm_loadl_epi64((const __m128i*) src); + __m128i dstABCD = _mm_loadl_epi64((__m128i*) dst); + uint32 mvX2 = *((uint32 *) const_cast(src_mv)); + + /* Remap colours. */ + if (mvX2 & 0x00FF00FF) { + #define CMOV_REMAP(m_colour, m_colour_init, m_src, m_m) \ + /* Written so the compiler uses CMOV. */ \ + Colour m_colour = m_colour_init; \ + { \ + const Colour srcm = (Colour) (m_src); \ + const uint m = (byte) (m_m); \ + const uint r = remap[m]; \ + const Colour cmap = (this->LookupColourInPalette(r).data & 0x00FFFFFF) | (srcm.data & 0xFF000000); \ + m_colour = r == 0 ? m_colour : cmap; \ + m_colour = m != 0 ? m_colour : srcm; \ + } +#ifdef _SQ64 + uint64 srcs = _mm_cvtsi128_si64(srcABCD); + uint64 remapped_src = 0; + CMOV_REMAP(c0, 0, srcs, mvX2); + remapped_src = c0.data; + CMOV_REMAP(c1, 0, srcs >> 32, mvX2 >> 16); + remapped_src |= (uint64) c1.data << 32; + srcABCD = _mm_cvtsi64_si128(remapped_src); +#else + Colour remapped_src[2]; + CMOV_REMAP(c0, 0, _mm_cvtsi128_si32(srcABCD), mvX2); + remapped_src[0] = c0.data; + CMOV_REMAP(c1, 0, src[1], mvX2 >> 16); + remapped_src[1] = c1.data; + srcABCD = _mm_loadl_epi64((__m128i*) &remapped_src); +#endif + + if ((mvX2 & 0xFF00FF00) != 0x80008000) srcABCD = AdjustBrightnessOfTwoPixels(srcABCD, mvX2); + } + + /* Blend colours. */ + _mm_storel_epi64((__m128i *) dst, AlphaBlendTwoPixels(srcABCD, dstABCD, ALPHA_BLEND_PARAM_1, ALPHA_BLEND_PARAM_2)); + dst += 2; + src += 2; + src_mv += 2; + } + + if ((bt_last == BT_NONE && effective_width & 1) || bt_last == BT_ODD) { +#else + for (uint x = (uint) effective_width; x > 0; x--) { +#endif + /* In case the m-channel is zero, do not remap this pixel in any way. */ + __m128i srcABCD; + if (src_mv->m) { + const uint r = remap[src_mv->m]; + if (r != 0) { + Colour remapped_colour = AdjustBrightneSSE(this->LookupColourInPalette(r), src_mv->v); + if (src->a == 255) { + *dst = remapped_colour; + } else { + remapped_colour.a = src->a; + srcABCD = _mm_cvtsi32_si128(remapped_colour.data); + goto bmcr_alpha_blend_single; + } + } + } else { + srcABCD = _mm_cvtsi32_si128(src->data); + if (src->a < 255) { +bmcr_alpha_blend_single: + __m128i dstABCD = _mm_cvtsi32_si128(dst->data); + srcABCD = AlphaBlendTwoPixels(srcABCD, dstABCD, ALPHA_BLEND_PARAM_1, ALPHA_BLEND_PARAM_2); + } + dst->data = _mm_cvtsi128_si32(srcABCD); + } +#if (SSE_VERSION == 2) + src_mv++; + dst++; + src++; +#endif + } + break; + + case BM_TRANSPARENT: + /* Make the current colour a bit more black, so it looks like this image is transparent. */ + for (uint x = (uint) bp->width / 2; x > 0; x--) { + __m128i srcABCD = _mm_loadl_epi64((const __m128i*) src); + __m128i dstABCD = _mm_loadl_epi64((__m128i*) dst); + _mm_storel_epi64((__m128i *) dst, DarkenTwoPixels(srcABCD, dstABCD, DARKEN_PARAM_1, DARKEN_PARAM_2)); + src += 2; + dst += 2; + } + + if ((bt_last == BT_NONE && bp->width & 1) || bt_last == BT_ODD) { + __m128i srcABCD = _mm_cvtsi32_si128(src->data); + __m128i dstABCD = _mm_cvtsi32_si128(dst->data); + dst->data = _mm_cvtsi128_si32(DarkenTwoPixels(srcABCD, dstABCD, DARKEN_PARAM_1, DARKEN_PARAM_2)); + } + break; + + case BM_CRASH_REMAP: + for (uint x = (uint) bp->width; x > 0; x--) { + if (src_mv->m == 0) { + if (src->a != 0) { + uint8 g = MakeDark(src->r, src->g, src->b); + *dst = ComposeColourRGBA(g, g, g, src->a, *dst); + } + } else { + uint r = remap[src_mv->m]; + if (r != 0) *dst = ComposeColourPANoCheck(this->AdjustBrightness(this->LookupColourInPalette(r), src_mv->v), src->a, *dst); + } + src_mv++; + dst++; + src++; + } + break; + + case BM_BLACK_REMAP: + for (uint x = (uint) bp->width; x > 0; x--) { + if (src->a != 0) { + *dst = Colour(0, 0, 0); + } + src_mv++; + dst++; + src++; + } + break; + } + +next_line: + if (mode == BM_COLOUR_REMAP || mode == BM_CRASH_REMAP) src_mv_line += si->sprite_width; + src_rgba_line = (const Colour*) ((const byte*) src_rgba_line + si->sprite_line_size); + dst_line += bp->pitch; + } +} +IGNORE_UNINITIALIZED_WARNING_STOP + +/** + * Draws a sprite to a (screen) buffer. Calls adequate templated function. + * + * @param bp further blitting parameters + * @param mode blitter mode + * @param zoom zoom level at which we are drawing + */ +#if (SSE_VERSION == 2) +void Blitter_32bppSSE2::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) +#elif (SSE_VERSION == 3) +void Blitter_32bppSSSE3::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) +#elif (SSE_VERSION == 4) +void Blitter_32bppSSE4::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) +#endif +{ + switch (mode) { + default: { + if (bp->skip_left != 0 || bp->width <= MARGIN_NORMAL_THRESHOLD) { +bm_normal: + const BlockType bt_last = (BlockType) (bp->width & 1); + switch (bt_last) { + default: Draw(bp, zoom); return; + case BT_ODD: Draw(bp, zoom); return; + } + } else { + if (((const Blitter_32bppSSE_Base::SpriteData *) bp->sprite)->flags & SF_TRANSLUCENT) { + Draw(bp, zoom); + } else { + Draw(bp, zoom); + } + return; + } + break; + } + case BM_COLOUR_REMAP: + if (((const Blitter_32bppSSE_Base::SpriteData *) bp->sprite)->flags & SF_NO_REMAP) goto bm_normal; + if (bp->skip_left != 0 || bp->width <= MARGIN_REMAP_THRESHOLD) { + Draw(bp, zoom); return; + } else { + Draw(bp, zoom); return; + } + case BM_TRANSPARENT: Draw(bp, zoom); return; + case BM_CRASH_REMAP: Draw(bp, zoom); return; + case BM_BLACK_REMAP: Draw(bp, zoom); return; + } +} +#endif /* FULL_ANIMATION */ + +#endif /* WITH_SSE */ +#endif /* BLITTER_32BPP_SSE_FUNC_HPP */ diff --git a/src/blitter/32bpp_sse_type.h b/src/blitter/32bpp_sse_type.h new file mode 100644 index 0000000..ac8da1b --- /dev/null +++ b/src/blitter/32bpp_sse_type.h @@ -0,0 +1,56 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file 32bpp_sse_type.hpp Types related to SSE 32 bpp blitter. */ + +#ifndef BLITTER_32BPP_SSE_TYPE_HPP +#define BLITTER_32BPP_SSE_TYPE_HPP + +#ifdef WITH_SSE + +#include "32bpp_simple.hpp" +#if (SSE_VERSION == 2) +#include +#elif (SSE_VERSION == 3) +#include +#elif (SSE_VERSION == 4) +#include +#endif + +#define META_LENGTH 2 ///< Number of uint32 inserted before each line of pixels in a sprite. +#define MARGIN_NORMAL_THRESHOLD (zoom == ZOOM_LVL_OUT_32X ? 8 : 4) ///< Minimum width to use margins with BM_NORMAL. +#define MARGIN_REMAP_THRESHOLD 4 ///< Minimum width to use margins with BM_COLOUR_REMAP. + +#ifdef _MSC_VER + #define ALIGN(n) __declspec(align(n)) +#else + #define ALIGN(n) __attribute__ ((aligned (n))) +#endif + +typedef union ALIGN(16) um128i { + __m128i m128i; + uint8 m128i_u8[16]; + uint16 m128i_u16[8]; + uint32 m128i_u32[4]; + uint64 m128i_u64[2]; +} um128i; + +#define CLEAR_HIGH_BYTE_MASK _mm_setr_epi8(-1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0) +#define ALPHA_CONTROL_MASK _mm_setr_epi8( 6, 7, 6, 7, 6, 7, -1, -1, 14, 15, 14, 15, 14, 15, -1, -1) +#define PACK_LOW_CONTROL_MASK _mm_setr_epi8( 0, 2, 4, -1, 8, 10, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1) +#define PACK_HIGH_CONTROL_MASK _mm_setr_epi8(-1, -1, -1, -1, -1, -1, -1, -1, 0, 2, 4, -1, 8, 10, 12, -1) +#define BRIGHTNESS_LOW_CONTROL_MASK _mm_setr_epi8( 1, 2, 1, 2, 1, 2, 0, 2, 3, 2, 3, 2, 3, 2, 0, 2) +#define BRIGHTNESS_DIV_CLEANER _mm_setr_epi8(-1, 1, -1, 1, -1, 1, -1, 0, -1, 1, -1, 1, -1, 1, -1, 0) +#define OVERBRIGHT_PRESENCE_MASK _mm_setr_epi8( 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0) +#define OVERBRIGHT_VALUE_MASK _mm_setr_epi8(-1, 0, -1, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, 0, 0) +#define OVERBRIGHT_CONTROL_MASK _mm_setr_epi8( 0, 1, 0, 1, 0, 1, 7, 7, 2, 3, 2, 3, 2, 3, 7, 7) +#define TRANSPARENT_NOM_BASE _mm_setr_epi16(256, 256, 256, 256, 256, 256, 256, 256) + +#endif /* WITH_SSE */ +#endif /* BLITTER_32BPP_SSE_TYPE_HPP */ diff --git a/src/blitter/32bpp_ssse3.cpp b/src/blitter/32bpp_ssse3.cpp new file mode 100644 index 0000000..ab6c9eb --- /dev/null +++ b/src/blitter/32bpp_ssse3.cpp @@ -0,0 +1,25 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file 32bpp_ssse3.cpp Implementation of the SSSE3 32 bpp blitter. */ + +#ifdef WITH_SSE + +#include "../stdafx.h" +#include "../zoom_func.h" +#include "../settings_type.h" +#include "32bpp_ssse3.hpp" +#include "32bpp_sse_func.hpp" + +#include "../safeguards.h" + +/** Instantiation of the SSSE3 32bpp blitter factory. */ +static FBlitter_32bppSSSE3 iFBlitter_32bppSSSE3; + +#endif /* WITH_SSE */ diff --git a/src/blitter/32bpp_ssse3.hpp b/src/blitter/32bpp_ssse3.hpp new file mode 100644 index 0000000..e9cac8f --- /dev/null +++ b/src/blitter/32bpp_ssse3.hpp @@ -0,0 +1,44 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file 32bpp_ssse3.hpp SSSE3 32 bpp blitter. */ + +#ifndef BLITTER_32BPP_SSSE3_HPP +#define BLITTER_32BPP_SSSE3_HPP + +#ifdef WITH_SSE + +#ifndef SSE_VERSION +#define SSE_VERSION 3 +#endif + +#ifndef FULL_ANIMATION +#define FULL_ANIMATION 0 +#endif + +#include "32bpp_sse2.hpp" + +/** The SSSE3 32 bpp blitter (without palette animation). */ +class Blitter_32bppSSSE3 : public Blitter_32bppSSE2 { +public: + /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); + template + void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom); + /* virtual */ const char *GetName() { return "32bpp-ssse3"; } +}; + +/** Factory for the SSSE3 32 bpp blitter (without palette animation). */ +class FBlitter_32bppSSSE3: public BlitterFactory { +public: + FBlitter_32bppSSSE3() : BlitterFactory("32bpp-ssse3", "32bpp SSSE3 Blitter (no palette animation)", HasCPUIDFlag(1, 2, 9)) {} + /* virtual */ Blitter *CreateInstance() { return new Blitter_32bppSSSE3(); } +}; + +#endif /* WITH_SSE */ +#endif /* BLITTER_32BPP_SSSE3_HPP */ diff --git a/src/blitter/8bpp_base.cpp b/src/blitter/8bpp_base.cpp new file mode 100644 index 0000000..eab6eaa --- /dev/null +++ b/src/blitter/8bpp_base.cpp @@ -0,0 +1,154 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file 8bpp_base.cpp Implementation of the base for all 8 bpp blitters. */ + +#include "../stdafx.h" +#include "../gfx_func.h" +#include "8bpp_base.hpp" + +#include "../safeguards.h" + +void Blitter_8bppBase::DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) +{ + const uint8 *ctab = GetNonSprite(pal, ST_RECOLOUR) + 1; + + do { + for (int i = 0; i != width; i++) *((uint8 *)dst + i) = ctab[((uint8 *)dst)[i]]; + dst = (uint8 *)dst + _screen.pitch; + } while (--height); +} + +void *Blitter_8bppBase::MoveTo(void *video, int x, int y) +{ + return (uint8 *)video + x + y * _screen.pitch; +} + +void Blitter_8bppBase::SetPixel(void *video, int x, int y, uint8 colour) +{ + *((uint8 *)video + x + y * _screen.pitch) = colour; +} + +void Blitter_8bppBase::DrawRect(void *video, int width, int height, uint8 colour) +{ + do { + memset(video, colour, width); + video = (uint8 *)video + _screen.pitch; + } while (--height); +} + +void Blitter_8bppBase::CopyFromBuffer(void *video, const void *src, int width, int height) +{ + uint8 *dst = (uint8 *)video; + const uint8 *usrc = (const uint8 *)src; + + for (; height > 0; height--) { + memcpy(dst, usrc, width * sizeof(uint8)); + usrc += width; + dst += _screen.pitch; + } +} + +void Blitter_8bppBase::CopyToBuffer(const void *video, void *dst, int width, int height) +{ + uint8 *udst = (uint8 *)dst; + const uint8 *src = (const uint8 *)video; + + for (; height > 0; height--) { + memcpy(udst, src, width * sizeof(uint8)); + src += _screen.pitch; + udst += width; + } +} + +void Blitter_8bppBase::CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) +{ + uint8 *udst = (uint8 *)dst; + const uint8 *src = (const uint8 *)video; + + for (; height > 0; height--) { + memcpy(udst, src, width * sizeof(uint8)); + src += _screen.pitch; + udst += dst_pitch; + } +} + +void Blitter_8bppBase::ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) +{ + const uint8 *src; + uint8 *dst; + + if (scroll_y > 0) { + /* Calculate pointers */ + dst = (uint8 *)video + left + (top + height - 1) * _screen.pitch; + src = dst - scroll_y * _screen.pitch; + + /* Decrease height and increase top */ + top += scroll_y; + height -= scroll_y; + assert(height > 0); + + /* Adjust left & width */ + if (scroll_x >= 0) { + dst += scroll_x; + left += scroll_x; + width -= scroll_x; + } else { + src -= scroll_x; + width += scroll_x; + } + + for (int h = height; h > 0; h--) { + memcpy(dst, src, width * sizeof(uint8)); + src -= _screen.pitch; + dst -= _screen.pitch; + } + } else { + /* Calculate pointers */ + dst = (uint8 *)video + left + top * _screen.pitch; + src = dst - scroll_y * _screen.pitch; + + /* Decrease height. (scroll_y is <=0). */ + height += scroll_y; + assert(height > 0); + + /* Adjust left & width */ + if (scroll_x >= 0) { + dst += scroll_x; + left += scroll_x; + width -= scroll_x; + } else { + src -= scroll_x; + width += scroll_x; + } + + /* the y-displacement may be 0 therefore we have to use memmove, + * because source and destination may overlap */ + for (int h = height; h > 0; h--) { + memmove(dst, src, width * sizeof(uint8)); + src += _screen.pitch; + dst += _screen.pitch; + } + } +} + +int Blitter_8bppBase::BufferSize(int width, int height) +{ + return width * height; +} + +void Blitter_8bppBase::PaletteAnimate(const Palette &palette) +{ + /* Video backend takes care of the palette animation */ +} + +Blitter::PaletteAnimation Blitter_8bppBase::UsePaletteAnimation() +{ + return Blitter::PALETTE_ANIMATION_VIDEO_BACKEND; +} diff --git a/src/blitter/8bpp_base.hpp b/src/blitter/8bpp_base.hpp new file mode 100644 index 0000000..2dff784 --- /dev/null +++ b/src/blitter/8bpp_base.hpp @@ -0,0 +1,35 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file 8bpp_base.hpp Base for all 8 bpp blitters. */ + +#ifndef BLITTER_8BPP_BASE_HPP +#define BLITTER_8BPP_BASE_HPP + +#include "base.hpp" + +/** Base for all 8bpp blitters. */ +class Blitter_8bppBase : public Blitter { +public: + /* virtual */ uint8 GetScreenDepth() { return 8; } + /* virtual */ void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal); + /* virtual */ void *MoveTo(void *video, int x, int y); + /* virtual */ void SetPixel(void *video, int x, int y, uint8 colour); + /* virtual */ void DrawRect(void *video, int width, int height, uint8 colour); + /* virtual */ void CopyFromBuffer(void *video, const void *src, int width, int height); + /* virtual */ void CopyToBuffer(const void *video, void *dst, int width, int height); + /* virtual */ void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch); + /* virtual */ void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y); + /* virtual */ int BufferSize(int width, int height); + /* virtual */ void PaletteAnimate(const Palette &palette); + /* virtual */ Blitter::PaletteAnimation UsePaletteAnimation(); + /* virtual */ int GetBytesPerPixel() { return 1; } +}; + +#endif /* BLITTER_8BPP_BASE_HPP */ diff --git a/src/blitter/8bpp_optimized.cpp b/src/blitter/8bpp_optimized.cpp new file mode 100644 index 0000000..0f07e7c --- /dev/null +++ b/src/blitter/8bpp_optimized.cpp @@ -0,0 +1,232 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file 8bpp_optimized.cpp Implementation of the optimized 8 bpp blitter. */ + +#include "../stdafx.h" +#include "../zoom_func.h" +#include "../settings_type.h" +#include "../core/math_func.hpp" +#include "../core/mem_func.hpp" +#include "8bpp_optimized.hpp" + +#include "../safeguards.h" + +/** Instantiation of the 8bpp optimised blitter factory. */ +static FBlitter_8bppOptimized iFBlitter_8bppOptimized; + +void Blitter_8bppOptimized::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) +{ + /* Find the offset of this zoom-level */ + const SpriteData *sprite_src = (const SpriteData *)bp->sprite; + uint offset = sprite_src->offset[zoom]; + + /* Find where to start reading in the source sprite */ + const uint8 *src = sprite_src->data + offset; + uint8 *dst_line = (uint8 *)bp->dst + bp->top * bp->pitch + bp->left; + + /* Skip over the top lines in the source image */ + for (int y = 0; y < bp->skip_top; y++) { + for (;;) { + uint trans = *src++; + uint pixels = *src++; + if (trans == 0 && pixels == 0) break; + src += pixels; + } + } + + const uint8 *src_next = src; + + for (int y = 0; y < bp->height; y++) { + uint8 *dst = dst_line; + dst_line += bp->pitch; + + uint skip_left = bp->skip_left; + int width = bp->width; + + for (;;) { + src = src_next; + uint trans = *src++; + uint pixels = *src++; + src_next = src + pixels; + if (trans == 0 && pixels == 0) break; + if (width <= 0) continue; + + if (skip_left != 0) { + if (skip_left < trans) { + trans -= skip_left; + skip_left = 0; + } else { + skip_left -= trans; + trans = 0; + } + if (skip_left < pixels) { + src += skip_left; + pixels -= skip_left; + skip_left = 0; + } else { + src += pixels; + skip_left -= pixels; + pixels = 0; + } + } + if (skip_left != 0) continue; + + /* Skip transparent pixels */ + dst += trans; + width -= trans; + if (width <= 0 || pixels == 0) continue; + pixels = min(pixels, (uint)width); + width -= pixels; + + switch (mode) { + case BM_COLOUR_REMAP: + case BM_CRASH_REMAP: { + const uint8 *remap = bp->remap; + do { + uint m = remap[*src]; + if (m != 0) *dst = m; + dst++; src++; + } while (--pixels != 0); + break; + } + + case BM_BLACK_REMAP: + MemSetT(dst, 0, pixels); + dst += pixels; + break; + + case BM_TRANSPARENT: { + const uint8 *remap = bp->remap; + src += pixels; + do { + *dst = remap[*dst]; + dst++; + } while (--pixels != 0); + break; + } + + default: + MemCpyT(dst, src, pixels); + dst += pixels; src += pixels; + break; + } + } + } +} + +Sprite *Blitter_8bppOptimized::Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) +{ + /* Make memory for all zoom-levels */ + uint memory = sizeof(SpriteData); + + ZoomLevel zoom_min; + ZoomLevel zoom_max; + + if (sprite->type == ST_FONT) { + zoom_min = ZOOM_LVL_NORMAL; + zoom_max = ZOOM_LVL_NORMAL; + } else { + zoom_min = _settings_client.gui.zoom_min; + zoom_max = _settings_client.gui.zoom_max; + if (zoom_max == zoom_min) zoom_max = ZOOM_LVL_MAX; + } + + for (ZoomLevel i = zoom_min; i <= zoom_max; i++) { + memory += sprite[i].width * sprite[i].height; + } + + /* We have no idea how much memory we really need, so just guess something */ + memory *= 5; + + /* Don't allocate memory each time, but just keep some + * memory around as this function is called quite often + * and the memory usage is quite low. */ + static ReusableBuffer temp_buffer; + SpriteData *temp_dst = (SpriteData *)temp_buffer.Allocate(memory); + memset(temp_dst, 0, sizeof(*temp_dst)); + byte *dst = temp_dst->data; + + /* Make the sprites per zoom-level */ + for (ZoomLevel i = zoom_min; i <= zoom_max; i++) { + /* Store the index table */ + uint offset = dst - temp_dst->data; + temp_dst->offset[i] = offset; + + /* cache values, because compiler can't cache it */ + int scaled_height = sprite[i].height; + int scaled_width = sprite[i].width; + + for (int y = 0; y < scaled_height; y++) { + uint trans = 0; + uint pixels = 0; + uint last_colour = 0; + byte *count_dst = NULL; + + /* Store the scaled image */ + const SpriteLoader::CommonPixel *src = &sprite[i].data[y * sprite[i].width]; + + for (int x = 0; x < scaled_width; x++) { + uint colour = src++->m; + + if (last_colour == 0 || colour == 0 || pixels == 255) { + if (count_dst != NULL) { + /* Write how many non-transparent bytes we get */ + *count_dst = pixels; + pixels = 0; + count_dst = NULL; + } + /* As long as we find transparency bytes, keep counting */ + if (colour == 0 && trans != 255) { + last_colour = 0; + trans++; + continue; + } + /* No longer transparency, so write the amount of transparent bytes */ + *dst = trans; + dst++; + trans = 0; + /* Reserve a byte for the pixel counter */ + count_dst = dst; + dst++; + } + last_colour = colour; + if (colour == 0) { + trans++; + } else { + pixels++; + *dst = colour; + dst++; + } + } + + if (count_dst != NULL) *count_dst = pixels; + + /* Write line-ending */ + *dst = 0; dst++; + *dst = 0; dst++; + } + } + + uint size = dst - (byte *)temp_dst; + + /* Safety check, to make sure we guessed the size correctly */ + assert(size < memory); + + /* Allocate the exact amount of memory we need */ + Sprite *dest_sprite = (Sprite *)allocator(sizeof(*dest_sprite) + size); + + dest_sprite->height = sprite->height; + dest_sprite->width = sprite->width; + dest_sprite->x_offs = sprite->x_offs; + dest_sprite->y_offs = sprite->y_offs; + memcpy(dest_sprite->data, temp_dst, size); + + return dest_sprite; +} diff --git a/src/blitter/8bpp_optimized.hpp b/src/blitter/8bpp_optimized.hpp new file mode 100644 index 0000000..b5b5324 --- /dev/null +++ b/src/blitter/8bpp_optimized.hpp @@ -0,0 +1,40 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file 8bpp_optimized.hpp An optimized 8 bpp blitter. */ + +#ifndef BLITTER_8BPP_OPTIMIZED_HPP +#define BLITTER_8BPP_OPTIMIZED_HPP + +#include "8bpp_base.hpp" +#include "factory.hpp" + +/** 8bpp blitter optimised for speed. */ +class Blitter_8bppOptimized FINAL : public Blitter_8bppBase { +public: + /** Data stored about a (single) sprite. */ + struct SpriteData { + uint32 offset[ZOOM_LVL_COUNT]; ///< Offsets (from .data) to streams for different zoom levels. + byte data[]; ///< Data, all zoomlevels. + }; + + /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); + /* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator); + + /* virtual */ const char *GetName() { return "8bpp-optimized"; } +}; + +/** Factory for the 8bpp blitter optimised for speed. */ +class FBlitter_8bppOptimized : public BlitterFactory { +public: + FBlitter_8bppOptimized() : BlitterFactory("8bpp-optimized", "8bpp Optimized Blitter (compression + all-ZoomLevel cache)") {} + /* virtual */ Blitter *CreateInstance() { return new Blitter_8bppOptimized(); } +}; + +#endif /* BLITTER_8BPP_OPTIMIZED_HPP */ diff --git a/src/blitter/8bpp_simple.cpp b/src/blitter/8bpp_simple.cpp new file mode 100644 index 0000000..ed5dd3f --- /dev/null +++ b/src/blitter/8bpp_simple.cpp @@ -0,0 +1,81 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file 8bpp_simple.cpp Implementation of the simple 8 bpp blitter. */ + +#include "../stdafx.h" +#include "../zoom_func.h" +#include "8bpp_simple.hpp" + +#include "../safeguards.h" + +/** Instantiation of the simple 8bpp blitter factory. */ +static FBlitter_8bppSimple iFBlitter_8bppSimple; + +void Blitter_8bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) +{ + const uint8 *src, *src_line; + uint8 *dst, *dst_line; + + /* Find where to start reading in the source sprite */ + src_line = (const uint8 *)bp->sprite + (bp->skip_top * bp->sprite_width + bp->skip_left) * ScaleByZoom(1, zoom); + dst_line = (uint8 *)bp->dst + bp->top * bp->pitch + bp->left; + + for (int y = 0; y < bp->height; y++) { + dst = dst_line; + dst_line += bp->pitch; + + src = src_line; + src_line += bp->sprite_width * ScaleByZoom(1, zoom); + + for (int x = 0; x < bp->width; x++) { + uint colour = 0; + + switch (mode) { + case BM_COLOUR_REMAP: + case BM_CRASH_REMAP: + colour = bp->remap[*src]; + break; + + case BM_TRANSPARENT: + if (*src != 0) colour = bp->remap[*dst]; + break; + + case BM_BLACK_REMAP: + colour = 0; + break; + + default: + colour = *src; + break; + } + if (colour != 0) *dst = colour; + dst++; + src += ScaleByZoom(1, zoom); + } + } +} + +Sprite *Blitter_8bppSimple::Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) +{ + Sprite *dest_sprite; + dest_sprite = (Sprite *)allocator(sizeof(*dest_sprite) + (size_t)sprite->height * (size_t)sprite->width); + + dest_sprite->height = sprite->height; + dest_sprite->width = sprite->width; + dest_sprite->x_offs = sprite->x_offs; + dest_sprite->y_offs = sprite->y_offs; + + /* Copy over only the 'remap' channel, as that is what we care about in 8bpp */ + for (int i = 0; i < sprite->height * sprite->width; i++) { + dest_sprite->data[i] = sprite->data[i].m; + } + + return dest_sprite; +} diff --git a/src/blitter/8bpp_simple.hpp b/src/blitter/8bpp_simple.hpp new file mode 100644 index 0000000..c00c75a --- /dev/null +++ b/src/blitter/8bpp_simple.hpp @@ -0,0 +1,34 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file 8bpp_simple.hpp Simple (and slow) 8 bpp blitter. */ + +#ifndef BLITTER_8BPP_SIMPLE_HPP +#define BLITTER_8BPP_SIMPLE_HPP + +#include "8bpp_base.hpp" +#include "factory.hpp" + +/** Most trivial 8bpp blitter. */ +class Blitter_8bppSimple FINAL : public Blitter_8bppBase { +public: + /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); + /* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator); + + /* virtual */ const char *GetName() { return "8bpp-simple"; } +}; + +/** Factory for the most trivial 8bpp blitter. */ +class FBlitter_8bppSimple : public BlitterFactory { +public: + FBlitter_8bppSimple() : BlitterFactory("8bpp-simple", "8bpp Simple Blitter (relative slow, but never wrong)") {} + /* virtual */ Blitter *CreateInstance() { return new Blitter_8bppSimple(); } +}; + +#endif /* BLITTER_8BPP_SIMPLE_HPP */ diff --git a/src/blitter/base.cpp b/src/blitter/base.cpp new file mode 100644 index 0000000..e83df2e --- /dev/null +++ b/src/blitter/base.cpp @@ -0,0 +1,138 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file base.cpp Implementation of the base for all blitters. */ + +#include "../stdafx.h" +#include "base.hpp" +#include "../core/math_func.hpp" + +#include "../safeguards.h" + +void Blitter::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash) +{ + int dy; + int dx; + int stepx; + int stepy; + + dy = (y2 - y) * 2; + if (dy < 0) { + dy = -dy; + stepy = -1; + } else { + stepy = 1; + } + + dx = (x2 - x) * 2; + if (dx < 0) { + dx = -dx; + stepx = -1; + } else { + stepx = 1; + } + + if (dx == 0 && dy == 0) { + /* The algorithm below cannot handle this special case; make it work at least for line width 1 */ + if (x >= 0 && x < screen_width && y >= 0 && y < screen_height) this->SetPixel(video, x, y, colour); + return; + } + + int frac_diff = width * max(dx, dy); + if (width > 1) { + /* compute frac_diff = width * sqrt(dx*dx + dy*dy) + * Start interval: + * max(dx, dy) <= sqrt(dx*dx + dy*dy) <= sqrt(2) * max(dx, dy) <= 3/2 * max(dx, dy) */ + int frac_sq = width * width * (dx * dx + dy * dy); + int frac_max = 3 * frac_diff / 2; + while (frac_diff < frac_max) { + int frac_test = (frac_diff + frac_max) / 2; + if (frac_test * frac_test < frac_sq) { + frac_diff = frac_test + 1; + } else { + frac_max = frac_test - 1; + } + } + } + + int gap = dash; + if (dash == 0) dash = 1; + int dash_count = 0; + if (dx > dy) { + int y_low = y; + int y_high = y; + int frac_low = dy - frac_diff / 2; + int frac_high = dy + frac_diff / 2; + + while (frac_low + dx / 2 < 0) { + frac_low += dx; + y_low -= stepy; + } + while (frac_high - dx / 2 >= 0) { + frac_high -= dx; + y_high += stepy; + } + x2 += stepx; + + while (x != x2) { + if (dash_count < dash && x >= 0 && x < screen_width) { + for (int y = y_low; y != y_high; y += stepy) { + if (y >= 0 && y < screen_height) this->SetPixel(video, x, y, colour); + } + } + if (frac_low >= 0) { + y_low += stepy; + frac_low -= dx; + } + if (frac_high >= 0) { + y_high += stepy; + frac_high -= dx; + } + x += stepx; + frac_low += dy; + frac_high += dy; + if (++dash_count >= dash + gap) dash_count = 0; + } + } else { + int x_low = x; + int x_high = x; + int frac_low = dx - frac_diff / 2; + int frac_high = dx + frac_diff / 2; + + while (frac_low + dy / 2 < 0) { + frac_low += dy; + x_low -= stepx; + } + while (frac_high - dy / 2 >= 0) { + frac_high -= dy; + x_high += stepx; + } + y2 += stepy; + + while (y != y2) { + if (dash_count < dash && y >= 0 && y < screen_height) { + for (int x = x_low; x != x_high; x += stepx) { + if (x >= 0 && x < screen_width) this->SetPixel(video, x, y, colour); + } + } + if (frac_low >= 0) { + x_low += stepx; + frac_low -= dy; + } + if (frac_high >= 0) { + x_high += stepx; + frac_high -= dy; + } + y += stepy; + frac_low += dx; + frac_high += dx; + if (++dash_count >= dash + gap) dash_count = 0; + } + } +} diff --git a/src/blitter/base.hpp b/src/blitter/base.hpp new file mode 100644 index 0000000..a9403b3 --- /dev/null +++ b/src/blitter/base.hpp @@ -0,0 +1,208 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file base.hpp Base for all blitters. */ + +#ifndef BLITTER_BASE_HPP +#define BLITTER_BASE_HPP + +#include "../spritecache.h" +#include "../spriteloader/spriteloader.hpp" + +/** The modes of blitting we can do. */ +enum BlitterMode { + BM_NORMAL, ///< Perform the simple blitting. + BM_COLOUR_REMAP, ///< Perform a colour remapping. + BM_TRANSPARENT, ///< Perform transparency colour remapping. + BM_CRASH_REMAP, ///< Perform a crash remapping. + BM_BLACK_REMAP, ///< Perform remapping to a completely blackened sprite +}; + +/** + * How all blitters should look like. Extend this class to make your own. + */ +class Blitter { +public: + /** Parameters related to blitting. */ + struct BlitterParams { + const void *sprite; ///< Pointer to the sprite how ever the encoder stored it + const byte *remap; ///< XXX -- Temporary storage for remap array + + int skip_left; ///< How much pixels of the source to skip on the left (based on zoom of dst) + int skip_top; ///< How much pixels of the source to skip on the top (based on zoom of dst) + int width; ///< The width in pixels that needs to be drawn to dst + int height; ///< The height in pixels that needs to be drawn to dst + int sprite_width; ///< Real width of the sprite + int sprite_height; ///< Real height of the sprite + int left; ///< The left offset in the 'dst' in pixels to start drawing + int top; ///< The top offset in the 'dst' in pixels to start drawing + + void *dst; ///< Destination buffer + int pitch; ///< The pitch of the destination buffer + }; + + /** Types of palette animation. */ + enum PaletteAnimation { + PALETTE_ANIMATION_NONE, ///< No palette animation + PALETTE_ANIMATION_VIDEO_BACKEND, ///< Palette animation should be done by video backend (8bpp only!) + PALETTE_ANIMATION_BLITTER, ///< The blitter takes care of the palette animation + }; + + /** + * Get the screen depth this blitter works for. + * This is either: 8, 16, 24 or 32. + */ + virtual uint8 GetScreenDepth() = 0; + + /** + * Draw an image to the screen, given an amount of params defined above. + */ + virtual void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) = 0; + + /** + * Draw a colourtable to the screen. This is: the colour of the screen is read + * and is looked-up in the palette to match a new colour, which then is put + * on the screen again. + * @param dst the destination pointer (video-buffer). + * @param width the width of the buffer. + * @param height the height of the buffer. + * @param pal the palette to use. + */ + virtual void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) = 0; + + /** + * Convert a sprite from the loader to our own format. + */ + virtual Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) = 0; + + /** + * Move the destination pointer the requested amount x and y, keeping in mind + * any pitch and bpp of the renderer. + * @param video The destination pointer (video-buffer) to scroll. + * @param x How much you want to scroll to the right. + * @param y How much you want to scroll to the bottom. + * @return A new destination pointer moved the the requested place. + */ + virtual void *MoveTo(void *video, int x, int y) = 0; + + /** + * Draw a pixel with a given colour on the video-buffer. + * @param video The destination pointer (video-buffer). + * @param x The x position within video-buffer. + * @param y The y position within video-buffer. + * @param colour A 8bpp mapping colour. + */ + virtual void SetPixel(void *video, int x, int y, uint8 colour) = 0; + + /** + * Make a single horizontal line in a single colour on the video-buffer. + * @param video The destination pointer (video-buffer). + * @param width The length of the line. + * @param height The height of the line. + * @param colour A 8bpp mapping colour. + */ + virtual void DrawRect(void *video, int width, int height, uint8 colour) = 0; + + /** + * Draw a line with a given colour. + * @param video The destination pointer (video-buffer). + * @param x The x coordinate from where the line starts. + * @param y The y coordinate from where the line starts. + * @param x2 The x coordinate to where the line goes. + * @param y2 The y coordinate to where the lines goes. + * @param screen_width The width of the screen you are drawing in (to avoid buffer-overflows). + * @param screen_height The height of the screen you are drawing in (to avoid buffer-overflows). + * @param colour A 8bpp mapping colour. + * @param width Line width. + * @param dash Length of dashes for dashed lines. 0 means solid line. + */ + virtual void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash = 0); + + /** + * Copy from a buffer to the screen. + * @param video The destination pointer (video-buffer). + * @param src The buffer from which the data will be read. + * @param width The width of the buffer. + * @param height The height of the buffer. + * @note You can not do anything with the content of the buffer, as the blitter can store non-pixel data in it too! + */ + virtual void CopyFromBuffer(void *video, const void *src, int width, int height) = 0; + + /** + * Copy from the screen to a buffer. + * @param video The destination pointer (video-buffer). + * @param dst The buffer in which the data will be stored. + * @param width The width of the buffer. + * @param height The height of the buffer. + * @note You can not do anything with the content of the buffer, as the blitter can store non-pixel data in it too! + */ + virtual void CopyToBuffer(const void *video, void *dst, int width, int height) = 0; + + /** + * Copy from the screen to a buffer in a palette format for 8bpp and RGBA format for 32bpp. + * @param video The destination pointer (video-buffer). + * @param dst The buffer in which the data will be stored. + * @param width The width of the buffer. + * @param height The height of the buffer. + * @param dst_pitch The pitch (byte per line) of the destination buffer. + */ + virtual void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) = 0; + + /** + * Scroll the videobuffer some 'x' and 'y' value. + * @param video The buffer to scroll into. + * @param left The left value of the screen to scroll. + * @param top The top value of the screen to scroll. + * @param width The width of the screen to scroll. + * @param height The height of the screen to scroll. + * @param scroll_x How much to scroll in X. + * @param scroll_y How much to scroll in Y. + */ + virtual void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) = 0; + + /** + * Calculate how much memory there is needed for an image of this size in the video-buffer. + * @param width The width of the buffer-to-be. + * @param height The height of the buffer-to-be. + * @return The size needed for the buffer. + */ + virtual int BufferSize(int width, int height) = 0; + + /** + * Called when the 8bpp palette is changed; you should redraw all pixels on the screen that + * are equal to the 8bpp palette indexes 'first_dirty' to 'first_dirty + count_dirty'. + * @param palette The new palette. + */ + virtual void PaletteAnimate(const Palette &palette) = 0; + + /** + * Check if the blitter uses palette animation at all. + * @return True if it uses palette animation. + */ + virtual Blitter::PaletteAnimation UsePaletteAnimation() = 0; + + /** + * Get the name of the blitter, the same as the Factory-instance returns. + */ + virtual const char *GetName() = 0; + + /** + * Get how many bytes are needed to store a pixel. + */ + virtual int GetBytesPerPixel() = 0; + + /** + * Post resize event + */ + virtual void PostResize() { }; + + virtual ~Blitter() { } +}; + +#endif /* BLITTER_BASE_HPP */ diff --git a/src/blitter/factory.hpp b/src/blitter/factory.hpp new file mode 100644 index 0000000..01faca6 --- /dev/null +++ b/src/blitter/factory.hpp @@ -0,0 +1,196 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file factory.hpp Factory to 'query' all available blitters. */ + +#ifndef BLITTER_FACTORY_HPP +#define BLITTER_FACTORY_HPP + +#include "base.hpp" +#include "../debug.h" +#include "../string_func.h" +#include "../core/string_compare_type.hpp" +#include + +#if defined(WITH_COCOA) +bool QZ_CanDisplay8bpp(); +#endif /* defined(WITH_COCOA) */ + +/** + * The base factory, keeping track of all blitters. + */ +class BlitterFactory { +private: + const char *name; ///< The name of the blitter factory. + const char *description; ///< The description of the blitter. + + typedef std::map Blitters; ///< Map of blitter factories. + + /** + * Get the map with currently known blitters. + * @return The known blitters. + */ + static Blitters &GetBlitters() + { + static Blitters &s_blitters = *new Blitters(); + return s_blitters; + } + + /** + * Get the currently active blitter. + * @return The currently active blitter. + */ + static Blitter **GetActiveBlitter() + { + static Blitter *s_blitter = NULL; + return &s_blitter; + } + +protected: + /** + * Construct the blitter, and register it. + * @param name The name of the blitter. + * @param description A longer description for the blitter. + * @param usable Whether the blitter is usable (on the current computer). For example for disabling SSE blitters when the CPU can't handle them. + * @pre name != NULL. + * @pre description != NULL. + * @pre There is no blitter registered with this name. + */ + BlitterFactory(const char *name, const char *description, bool usable = true) : + name(stredup(name)), description(stredup(description)) + { + if (usable) { + /* + * Only add when the blitter is usable. Do not bail out or + * do more special things since the blitters are always + * instantiated upon start anyhow and freed upon shutdown. + */ + std::pair P = GetBlitters().insert(Blitters::value_type(this->name, this)); + assert(P.second); + } else { + DEBUG(driver, 1, "Not registering blitter %s as it is not usable", name); + } + } + +public: + virtual ~BlitterFactory() + { + GetBlitters().erase(this->name); + if (GetBlitters().empty()) delete &GetBlitters(); + + free(this->name); + free(this->description); + } + + /** + * Find the requested blitter and return his class. + * @param name the blitter to select. + * @post Sets the blitter so GetCurrentBlitter() returns it too. + */ + static Blitter *SelectBlitter(const char *name) + { + BlitterFactory *b = GetBlitterFactory(name); + if (b == NULL) return NULL; + + Blitter *newb = b->CreateInstance(); + delete *GetActiveBlitter(); + *GetActiveBlitter() = newb; + + DEBUG(driver, 1, "Successfully %s blitter '%s'", StrEmpty(name) ? "probed" : "loaded", newb->GetName()); + return newb; + } + + /** + * Get the blitter factory with the given name. + * @param name the blitter factory to select. + * @return The blitter factory, or NULL when there isn't one with the wanted name. + */ + static BlitterFactory *GetBlitterFactory(const char *name) + { +#if defined(DEDICATED) + const char *default_blitter = "null"; +#else + const char *default_blitter = "8bpp-optimized"; + +#if defined(WITH_COCOA) + /* Some people reported lack of fullscreen support in 8 bpp mode. + * While we prefer 8 bpp since it's faster, we will still have to test for support. */ + if (!QZ_CanDisplay8bpp()) { + /* The main display can't go to 8 bpp fullscreen mode. + * We will have to switch to 32 bpp by default. */ + default_blitter = "32bpp-anim"; + } +#endif /* defined(WITH_COCOA) */ +#endif /* defined(DEDICATED) */ + if (GetBlitters().size() == 0) return NULL; + const char *bname = (StrEmpty(name)) ? default_blitter : name; + + Blitters::iterator it = GetBlitters().begin(); + for (; it != GetBlitters().end(); it++) { + BlitterFactory *b = (*it).second; + if (strcasecmp(bname, b->name) == 0) { + return b; + } + } + return NULL; + } + + /** + * Get the current active blitter (always set by calling SelectBlitter). + */ + static Blitter *GetCurrentBlitter() + { + return *GetActiveBlitter(); + } + + /** + * Fill a buffer with information about the blitters. + * @param p The buffer to fill. + * @param last The last element of the buffer. + * @return p The location till where we filled the buffer. + */ + static char *GetBlittersInfo(char *p, const char *last) + { + p += seprintf(p, last, "List of blitters:\n"); + Blitters::iterator it = GetBlitters().begin(); + for (; it != GetBlitters().end(); it++) { + BlitterFactory *b = (*it).second; + p += seprintf(p, last, "%18s: %s\n", b->name, b->GetDescription()); + } + p += seprintf(p, last, "\n"); + + return p; + } + + /** + * Get the long, human readable, name for the Blitter-class. + */ + const char *GetName() const + { + return this->name; + } + + /** + * Get a nice description of the blitter-class. + */ + const char *GetDescription() const + { + return this->description; + } + + /** + * Create an instance of this Blitter-class. + */ + virtual Blitter *CreateInstance() = 0; +}; + +extern char *_ini_blitter; +extern bool _blitter_autodetected; + +#endif /* BLITTER_FACTORY_HPP */ diff --git a/src/blitter/null.cpp b/src/blitter/null.cpp new file mode 100644 index 0000000..e968abe --- /dev/null +++ b/src/blitter/null.cpp @@ -0,0 +1,31 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file null.cpp A blitter that doesn't blit. */ + +#include "../stdafx.h" +#include "null.hpp" + +#include "../safeguards.h" + +/** Instantiation of the null blitter factory. */ +static FBlitter_Null iFBlitter_Null; + +Sprite *Blitter_Null::Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) +{ + Sprite *dest_sprite; + dest_sprite = (Sprite *)allocator(sizeof(*dest_sprite)); + + dest_sprite->height = sprite->height; + dest_sprite->width = sprite->width; + dest_sprite->x_offs = sprite->x_offs; + dest_sprite->y_offs = sprite->y_offs; + + return dest_sprite; +} diff --git a/src/blitter/null.hpp b/src/blitter/null.hpp new file mode 100644 index 0000000..a6fed2e --- /dev/null +++ b/src/blitter/null.hpp @@ -0,0 +1,47 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file null.hpp The blitter that doesn't blit. */ + +#ifndef BLITTER_NULL_HPP +#define BLITTER_NULL_HPP + +#include "factory.hpp" + +/** Blitter that does nothing. */ +class Blitter_Null : public Blitter { +public: + /* virtual */ uint8 GetScreenDepth() { return 0; } + /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) {}; + /* virtual */ void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) {}; + /* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator); + /* virtual */ void *MoveTo(void *video, int x, int y) { return NULL; }; + /* virtual */ void SetPixel(void *video, int x, int y, uint8 colour) {}; + /* virtual */ void DrawRect(void *video, int width, int height, uint8 colour) {}; + /* virtual */ void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash) {}; + /* virtual */ void CopyFromBuffer(void *video, const void *src, int width, int height) {}; + /* virtual */ void CopyToBuffer(const void *video, void *dst, int width, int height) {}; + /* virtual */ void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) {}; + /* virtual */ void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) {}; + /* virtual */ int BufferSize(int width, int height) { return 0; }; + /* virtual */ void PaletteAnimate(const Palette &palette) { }; + /* virtual */ Blitter::PaletteAnimation UsePaletteAnimation() { return Blitter::PALETTE_ANIMATION_NONE; }; + + /* virtual */ const char *GetName() { return "null"; } + /* virtual */ int GetBytesPerPixel() { return 0; } +}; + +/** Factory for the blitter that does nothing. */ +class FBlitter_Null : public BlitterFactory { +public: + FBlitter_Null() : BlitterFactory("null", "Null Blitter (does nothing)") {} + /* virtual */ Blitter *CreateInstance() { return new Blitter_Null(); } +}; + +#endif /* BLITTER_NULL_HPP */ diff --git a/src/bmp.cpp b/src/bmp.cpp new file mode 100644 index 0000000..1033d89 --- /dev/null +++ b/src/bmp.cpp @@ -0,0 +1,419 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file bmp.cpp Read and write support for bmps. */ + +#include "stdafx.h" +#include "bmp.h" +#include "core/bitmath_func.hpp" +#include "core/alloc_func.hpp" +#include "core/mem_func.hpp" + +#include "safeguards.h" + +void BmpInitializeBuffer(BmpBuffer *buffer, FILE *file) +{ + buffer->pos = -1; + buffer->file = file; + buffer->read = 0; + buffer->real_pos = ftell(file); +} + +static inline void AdvanceBuffer(BmpBuffer *buffer) +{ + if (buffer->read < 0) return; + + buffer->read = (int)fread(buffer->data, 1, BMP_BUFFER_SIZE, buffer->file); + buffer->pos = 0; +} + +static inline bool EndOfBuffer(BmpBuffer *buffer) +{ + if (buffer->read < 0) return false; + + if (buffer->pos == buffer->read || buffer->pos < 0) AdvanceBuffer(buffer); + return buffer->pos == buffer->read; +} + +static inline byte ReadByte(BmpBuffer *buffer) +{ + if (buffer->read < 0) return 0; + + if (buffer->pos == buffer->read || buffer->pos < 0) AdvanceBuffer(buffer); + buffer->real_pos++; + return buffer->data[buffer->pos++]; +} + +static inline uint16 ReadWord(BmpBuffer *buffer) +{ + uint16 var = ReadByte(buffer); + return var | (ReadByte(buffer) << 8); +} + +static inline uint32 ReadDword(BmpBuffer *buffer) +{ + uint32 var = ReadWord(buffer); + return var | (ReadWord(buffer) << 16); +} + +static inline void SkipBytes(BmpBuffer *buffer, int bytes) +{ + int i; + for (i = 0; i < bytes; i++) ReadByte(buffer); +} + +static inline void SetStreamOffset(BmpBuffer *buffer, int offset) +{ + if (fseek(buffer->file, offset, SEEK_SET) < 0) { + buffer->read = -1; + } + buffer->pos = -1; + buffer->real_pos = offset; + AdvanceBuffer(buffer); +} + +/** + * Reads a 1 bpp uncompressed bitmap + * The bitmap is converted to a 8 bpp bitmap + */ +static inline bool BmpRead1(BmpBuffer *buffer, BmpInfo *info, BmpData *data) +{ + uint x, y, i; + byte pad = GB(4 - info->width / 8, 0, 2); + byte *pixel_row; + byte b; + for (y = info->height; y > 0; y--) { + x = 0; + pixel_row = &data->bitmap[(y - 1) * info->width]; + while (x < info->width) { + if (EndOfBuffer(buffer)) return false; // the file is shorter than expected + b = ReadByte(buffer); + for (i = 8; i > 0; i--) { + if (x < info->width) *pixel_row++ = GB(b, i - 1, 1); + x++; + } + } + /* Padding for 32 bit align */ + SkipBytes(buffer, pad); + } + return true; +} + +/** + * Reads a 4 bpp uncompressed bitmap + * The bitmap is converted to a 8 bpp bitmap + */ +static inline bool BmpRead4(BmpBuffer *buffer, BmpInfo *info, BmpData *data) +{ + uint x, y; + byte pad = GB(4 - info->width / 2, 0, 2); + byte *pixel_row; + byte b; + for (y = info->height; y > 0; y--) { + x = 0; + pixel_row = &data->bitmap[(y - 1) * info->width]; + while (x < info->width) { + if (EndOfBuffer(buffer)) return false; // the file is shorter than expected + b = ReadByte(buffer); + *pixel_row++ = GB(b, 4, 4); + x++; + if (x < info->width) { + *pixel_row++ = GB(b, 0, 4); + x++; + } + } + /* Padding for 32 bit align */ + SkipBytes(buffer, pad); + } + return true; +} + +/** + * Reads a 4-bit RLE compressed bitmap + * The bitmap is converted to a 8 bpp bitmap + */ +static inline bool BmpRead4Rle(BmpBuffer *buffer, BmpInfo *info, BmpData *data) +{ + uint x = 0; + uint y = info->height - 1; + byte *pixel = &data->bitmap[y * info->width]; + while (y != 0 || x < info->width) { + if (EndOfBuffer(buffer)) return false; // the file is shorter than expected + + byte n = ReadByte(buffer); + byte c = ReadByte(buffer); + if (n == 0) { + switch (c) { + case 0: // end of line + x = 0; + if (y == 0) return false; + pixel = &data->bitmap[--y * info->width]; + break; + + case 1: // end of bitmap + return true; + + case 2: { // delta + if (EndOfBuffer(buffer)) return false; + byte dx = ReadByte(buffer); + byte dy = ReadByte(buffer); + + /* Check for over- and underflow. */ + if (x + dx >= info->width || x + dx < x || dy > y) return false; + + x += dx; + y -= dy; + pixel = &data->bitmap[y * info->width + x]; + break; + } + + default: { // uncompressed + uint i = 0; + while (i++ < c) { + if (EndOfBuffer(buffer) || x >= info->width) return false; + byte b = ReadByte(buffer); + *pixel++ = GB(b, 4, 4); + x++; + if (i++ < c) { + if (x >= info->width) return false; + *pixel++ = GB(b, 0, 4); + x++; + } + } + /* Padding for 16 bit align */ + SkipBytes(buffer, ((c + 1) / 2) % 2); + break; + } + } + } else { + /* Apparently it is common to encounter BMPs where the count of + * pixels to be written is higher than the remaining line width. + * Ignore the superfluous pixels instead of reporting an error. */ + uint i = 0; + while (x < info->width && i++ < n) { + *pixel++ = GB(c, 4, 4); + x++; + if (x < info->width && i++ < n) { + *pixel++ = GB(c, 0, 4); + x++; + } + } + } + } + return true; +} + +/** + * Reads a 8 bpp bitmap + */ +static inline bool BmpRead8(BmpBuffer *buffer, BmpInfo *info, BmpData *data) +{ + uint i; + uint y; + byte pad = GB(4 - info->width, 0, 2); + byte *pixel; + for (y = info->height; y > 0; y--) { + if (EndOfBuffer(buffer)) return false; // the file is shorter than expected + pixel = &data->bitmap[(y - 1) * info->width]; + for (i = 0; i < info->width; i++) *pixel++ = ReadByte(buffer); + /* Padding for 32 bit align */ + SkipBytes(buffer, pad); + } + return true; +} + +/** + * Reads a 8-bit RLE compressed bpp bitmap + */ +static inline bool BmpRead8Rle(BmpBuffer *buffer, BmpInfo *info, BmpData *data) +{ + uint x = 0; + uint y = info->height - 1; + byte *pixel = &data->bitmap[y * info->width]; + while (y != 0 || x < info->width) { + if (EndOfBuffer(buffer)) return false; // the file is shorter than expected + + byte n = ReadByte(buffer); + byte c = ReadByte(buffer); + if (n == 0) { + switch (c) { + case 0: // end of line + x = 0; + if (y == 0) return false; + pixel = &data->bitmap[--y * info->width]; + break; + + case 1: // end of bitmap + return true; + + case 2: { // delta + if (EndOfBuffer(buffer)) return false; + byte dx = ReadByte(buffer); + byte dy = ReadByte(buffer); + + /* Check for over- and underflow. */ + if (x + dx >= info->width || x + dx < x || dy > y) return false; + + x += dx; + y -= dy; + pixel = &data->bitmap[y * info->width + x]; + break; + } + + default: { // uncompressed + for (uint i = 0; i < c; i++) { + if (EndOfBuffer(buffer) || x >= info->width) return false; + *pixel++ = ReadByte(buffer); + x++; + } + /* Padding for 16 bit align */ + SkipBytes(buffer, c % 2); + break; + } + } + } else { + /* Apparently it is common to encounter BMPs where the count of + * pixels to be written is higher than the remaining line width. + * Ignore the superfluous pixels instead of reporting an error. */ + for (uint i = 0; x < info->width && i < n; i++) { + *pixel++ = c; + x++; + } + } + } + return true; +} + +/** + * Reads a 24 bpp uncompressed bitmap + */ +static inline bool BmpRead24(BmpBuffer *buffer, BmpInfo *info, BmpData *data) +{ + uint x, y; + byte pad = GB(4 - info->width * 3, 0, 2); + byte *pixel_row; + for (y = info->height; y > 0; y--) { + pixel_row = &data->bitmap[(y - 1) * info->width * 3]; + for (x = 0; x < info->width; x++) { + if (EndOfBuffer(buffer)) return false; // the file is shorter than expected + *(pixel_row + 2) = ReadByte(buffer); // green + *(pixel_row + 1) = ReadByte(buffer); // blue + *pixel_row = ReadByte(buffer); // red + pixel_row += 3; + } + /* Padding for 32 bit align */ + SkipBytes(buffer, pad); + } + return true; +} + +/* + * Reads bitmap headers, and palette (if any) + */ +bool BmpReadHeader(BmpBuffer *buffer, BmpInfo *info, BmpData *data) +{ + uint32 header_size; + assert(info != NULL); + MemSetT(info, 0); + + /* Reading BMP header */ + if (ReadWord(buffer) != 0x4D42) return false; // signature should be 'BM' + SkipBytes(buffer, 8); // skip file size and reserved + info->offset = ReadDword(buffer); + + /* Reading info header */ + header_size = ReadDword(buffer); + if (header_size < 12) return false; // info header should be at least 12 bytes long + + info->os2_bmp = (header_size == 12); // OS/2 1.x or windows 2.x info header is 12 bytes long + + if (info->os2_bmp) { + info->width = ReadWord(buffer); + info->height = ReadWord(buffer); + header_size -= 8; + } else { + info->width = ReadDword(buffer); + info->height = ReadDword(buffer); + header_size -= 12; + } + + if (ReadWord(buffer) != 1) return false; // BMP can have only 1 plane + + info->bpp = ReadWord(buffer); + if (info->bpp != 1 && info->bpp != 4 && info->bpp != 8 && info->bpp != 24) { + /* Only 1 bpp, 4 bpp, 8bpp and 24 bpp bitmaps are supported */ + return false; + } + + /* Reads compression method if available in info header*/ + if ((header_size -= 4) >= 4) { + info->compression = ReadDword(buffer); + header_size -= 4; + } + + /* Only 4-bit and 8-bit rle compression is supported */ + if (info->compression > 2 || (info->compression > 0 && !(info->bpp == 4 || info->bpp == 8))) return false; + + if (info->bpp <= 8) { + uint i; + + /* Reads number of colours if available in info header */ + if (header_size >= 16) { + SkipBytes(buffer, 12); // skip image size and resolution + info->palette_size = ReadDword(buffer); // number of colours in palette + SkipBytes(buffer, header_size - 16); // skip the end of info header + } + if (info->palette_size == 0) info->palette_size = 1 << info->bpp; + + data->palette = CallocT(info->palette_size); + + for (i = 0; i < info->palette_size; i++) { + data->palette[i].b = ReadByte(buffer); + data->palette[i].g = ReadByte(buffer); + data->palette[i].r = ReadByte(buffer); + if (!info->os2_bmp) SkipBytes(buffer, 1); // unused + } + } + + return buffer->real_pos <= info->offset; +} + +/* + * Reads the bitmap + * 1 bpp and 4 bpp bitmaps are converted to 8 bpp bitmaps + */ +bool BmpReadBitmap(BmpBuffer *buffer, BmpInfo *info, BmpData *data) +{ + assert(info != NULL && data != NULL); + + data->bitmap = CallocT(info->width * info->height * ((info->bpp == 24) ? 3 : 1)); + + /* Load image */ + SetStreamOffset(buffer, info->offset); + switch (info->compression) { + case 0: // no compression + switch (info->bpp) { + case 1: return BmpRead1(buffer, info, data); + case 4: return BmpRead4(buffer, info, data); + case 8: return BmpRead8(buffer, info, data); + case 24: return BmpRead24(buffer, info, data); + default: NOT_REACHED(); + } + case 1: return BmpRead8Rle(buffer, info, data); // 8-bit RLE compression + case 2: return BmpRead4Rle(buffer, info, data); // 4-bit RLE compression + default: NOT_REACHED(); + } +} + +void BmpDestroyData(BmpData *data) +{ + assert(data != NULL); + free(data->palette); + free(data->bitmap); +} diff --git a/src/bmp.h b/src/bmp.h new file mode 100644 index 0000000..cf2b538 --- /dev/null +++ b/src/bmp.h @@ -0,0 +1,47 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file bmp.h Read and write support for bmps. */ + +#ifndef BMP_H +#define BMP_H + +#include "gfx_type.h" + +struct BmpInfo { + uint32 offset; ///< offset of bitmap data from .bmp file begining + uint32 width; ///< bitmap width + uint32 height; ///< bitmap height + bool os2_bmp; ///< true if OS/2 1.x or windows 2.x bitmap + uint16 bpp; ///< bits per pixel + uint32 compression; ///< compression method (0 = none, 1 = 8-bit RLE, 2 = 4-bit RLE) + uint32 palette_size; ///< number of colours in palette +}; + +struct BmpData { + Colour *palette; + byte *bitmap; +}; + +#define BMP_BUFFER_SIZE 1024 + +struct BmpBuffer { + byte data[BMP_BUFFER_SIZE]; + int pos; + int read; + FILE *file; + uint real_pos; +}; + +void BmpInitializeBuffer(BmpBuffer *buffer, FILE *file); +bool BmpReadHeader(BmpBuffer *buffer, BmpInfo *info, BmpData *data); +bool BmpReadBitmap(BmpBuffer *buffer, BmpInfo *info, BmpData *data); +void BmpDestroyData(BmpData *data); + +#endif /* BMP_H */ diff --git a/src/bootstrap_gui.cpp b/src/bootstrap_gui.cpp new file mode 100644 index 0000000..7abc385 --- /dev/null +++ b/src/bootstrap_gui.cpp @@ -0,0 +1,269 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file bootstrap_gui.cpp Barely used user interface for bootstrapping OpenTTD, i.e. downloading the required content. */ + +#include "stdafx.h" +#include "base_media_base.h" +#include "blitter/factory.hpp" + +#if defined(ENABLE_NETWORK) && defined(WITH_FREETYPE) + +#include "core/geometry_func.hpp" +#include "fontcache.h" +#include "gfx_func.h" +#include "network/network.h" +#include "network/network_content_gui.h" +#include "openttd.h" +#include "strings_func.h" +#include "video/video_driver.hpp" +#include "window_func.h" + +#include "widgets/bootstrap_widget.h" + +#include "table/strings.h" + +#include "safeguards.h" + +/** Widgets for the background window to prevent smearing. */ +static const struct NWidgetPart _background_widgets[] = { + NWidget(WWT_PANEL, COLOUR_DARK_BLUE, WID_BB_BACKGROUND), SetResize(1, 1), +}; + +/** + * Window description for the background window to prevent smearing. + */ +static WindowDesc _background_desc( + WDP_MANUAL, NULL, 0, 0, + WC_BOOTSTRAP, WC_NONE, + 0, + _background_widgets, lengthof(_background_widgets) +); + +/** The background for the game. */ +class BootstrapBackground : public Window { +public: + BootstrapBackground() : Window(&_background_desc) + { + this->InitNested(0); + CLRBITS(this->flags, WF_WHITE_BORDER); + ResizeWindow(this, _screen.width, _screen.height); + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + GfxFillRect(r.left, r.top, r.right, r.bottom, 4, FILLRECT_OPAQUE); + GfxFillRect(r.left, r.top, r.right, r.bottom, 0, FILLRECT_CHECKER); + } +}; + +/** Nested widgets for the download window. */ +static const NWidgetPart _nested_boostrap_download_status_window_widgets[] = { + NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_CONTENT_DOWNLOAD_TITLE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_PANEL, COLOUR_GREY, WID_NCDS_BACKGROUND), + NWidget(NWID_SPACER), SetMinimalSize(350, 0), SetMinimalTextLines(3, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 30), + EndContainer(), +}; + +/** Window description for the download window */ +static WindowDesc _bootstrap_download_status_window_desc( + WDP_CENTER, NULL, 0, 0, + WC_NETWORK_STATUS_WINDOW, WC_NONE, + WDF_MODAL, + _nested_boostrap_download_status_window_widgets, lengthof(_nested_boostrap_download_status_window_widgets) +); + + +/** Window for showing the download status of content */ +struct BootstrapContentDownloadStatusWindow : public BaseNetworkContentDownloadStatusWindow { +public: + /** Simple call the constructor of the superclass. */ + BootstrapContentDownloadStatusWindow() : BaseNetworkContentDownloadStatusWindow(&_bootstrap_download_status_window_desc) + { + } + + virtual void OnDownloadComplete(ContentID cid) + { + /* We have completed downloading. We can trigger finding the right set now. */ + BaseGraphics::FindSets(); + + /* And continue going into the menu. */ + _game_mode = GM_MENU; + + /* _exit_game is used to break out of the outer video driver's MainLoop. */ + _exit_game = true; + delete this; + } +}; + +/** The widgets for the query. It has no close box as that sprite does not exist yet. */ +static const NWidgetPart _bootstrap_query_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_MISSING_GRAPHICS_SET_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BAFD_QUESTION), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BAFD_YES), SetDataTip(STR_MISSING_GRAPHICS_YES_DOWNLOAD, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BAFD_NO), SetDataTip(STR_MISSING_GRAPHICS_NO_QUIT, STR_NULL), + EndContainer(), + EndContainer(), +}; + +/** The window description for the query. */ +static WindowDesc _bootstrap_query_desc( + WDP_CENTER, NULL, 0, 0, + WC_CONFIRM_POPUP_QUERY, WC_NONE, + 0, + _bootstrap_query_widgets, lengthof(_bootstrap_query_widgets) +); + +/** The window for the query. It can't use the generic query window as that uses sprites that don't exist yet. */ +class BootstrapAskForDownloadWindow : public Window, ContentCallback { + Dimension button_size; ///< The dimension of the button + +public: + /** Start listening to the content client events. */ + BootstrapAskForDownloadWindow() : Window(&_bootstrap_query_desc) + { + this->InitNested(WN_CONFIRM_POPUP_QUERY_BOOTSTRAP); + _network_content_client.AddCallback(this); + } + + /** Stop listening to the content client events. */ + ~BootstrapAskForDownloadWindow() + { + _network_content_client.RemoveCallback(this); + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + /* We cache the button size. This is safe as no reinit can happen here. */ + if (this->button_size.width == 0) { + this->button_size = maxdim(GetStringBoundingBox(STR_MISSING_GRAPHICS_YES_DOWNLOAD), GetStringBoundingBox(STR_MISSING_GRAPHICS_NO_QUIT)); + this->button_size.width += WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; + this->button_size.height += WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM; + } + + switch (widget) { + case WID_BAFD_QUESTION: + /* The question is twice as wide as the buttons, and determine the height based on the width. */ + size->width = this->button_size.width * 2; + size->height = GetStringHeight(STR_MISSING_GRAPHICS_SET_MESSAGE, size->width - WD_FRAMETEXT_LEFT - WD_FRAMETEXT_RIGHT) + WD_FRAMETEXT_BOTTOM + WD_FRAMETEXT_TOP; + break; + + case WID_BAFD_YES: + case WID_BAFD_NO: + *size = this->button_size; + break; + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + if (widget != 0) return; + + DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top + WD_FRAMETEXT_TOP, r.bottom - WD_FRAMETEXT_BOTTOM, STR_MISSING_GRAPHICS_SET_MESSAGE, TC_FROMSTRING, SA_CENTER); + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_BAFD_YES: + /* We got permission to connect! Yay! */ + _network_content_client.Connect(); + break; + + case WID_BAFD_NO: + _exit_game = true; + break; + + default: + break; + } + } + + virtual void OnConnect(bool success) + { + /* Once connected, request the metadata. */ + _network_content_client.RequestContentList(CONTENT_TYPE_BASE_GRAPHICS); + } + + virtual void OnReceiveContentInfo(const ContentInfo *ci) + { + /* And once the meta data is received, start downloading it. */ + _network_content_client.Select(ci->id); + new BootstrapContentDownloadStatusWindow(); + delete this; + } +}; + +#endif /* defined(ENABLE_NETWORK) && defined(WITH_FREETYPE) */ + +/** + * Handle all procedures for bootstrapping OpenTTD without a base graphics set. + * This requires all kinds of trickery that is needed to avoid the use of + * sprites from the base graphics set which are pretty interwoven. + * @return True if a base set exists, otherwise false. + */ +bool HandleBootstrap() +{ + if (BaseGraphics::GetUsedSet() != NULL) return true; + + /* No user interface, bail out with an error. */ + if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 0) goto failure; + + /* If there is no network or no freetype, then there is nothing we can do. Go straight to failure. */ +#if defined(ENABLE_NETWORK) && defined(WITH_FREETYPE) && (defined(WITH_FONTCONFIG) || defined(WIN32) || defined(__APPLE__)) + if (!_network_available) goto failure; + + /* First tell the game we're bootstrapping. */ + _game_mode = GM_BOOTSTRAP; + + /* Initialise the freetype font code. */ + InitializeUnicodeGlyphMap(); + /* Next "force" finding a suitable freetype font as the local font is missing. */ + CheckForMissingGlyphs(false); + + /* Initialise the palette. The biggest step is 'faking' some recolour sprites. + * This way the mauve and gray colours work and we can show the user interface. */ + GfxInitPalettes(); + static const int offsets[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0, 0, 0, 0x04, 0x08 }; + for (uint i = 0; i != 16; i++) { + for (int j = 0; j < 8; j++) { + _colour_gradient[i][j] = offsets[i] + j; + } + } + + /* Finally ask the question. */ + new BootstrapBackground(); + new BootstrapAskForDownloadWindow(); + + /* Process the user events. */ + VideoDriver::GetInstance()->MainLoop(); + + /* _exit_game is used to get out of the video driver's main loop. + * In case GM_BOOTSTRAP is still set we did not exit it via the + * "download complete" event, so it was a manual exit. Obey it. */ + _exit_game = _game_mode == GM_BOOTSTRAP; + if (_exit_game) return false; + + /* Try to probe the graphics. Should work this time. */ + if (!BaseGraphics::SetSet(NULL)) goto failure; + + /* Finally we can continue heading for the menu. */ + _game_mode = GM_MENU; + return true; +#endif + + /* Failure to get enough working to get a graphics set. */ +failure: + usererror("Failed to find a graphics set. Please acquire a graphics set for OpenTTD. See section 4.1 of readme.txt."); + return false; +} diff --git a/src/bridge.h b/src/bridge.h new file mode 100644 index 0000000..badf045 --- /dev/null +++ b/src/bridge.h @@ -0,0 +1,80 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file bridge.h Header file for bridges */ + +#ifndef BRIDGE_H +#define BRIDGE_H + +#include "gfx_type.h" +#include "tile_cmd.h" + +/** + * This enum is related to the definition of bridge pieces, + * which is used to determine the proper sprite table to use + * while drawing a given bridge part. + */ +enum BridgePieces { + BRIDGE_PIECE_NORTH = 0, + BRIDGE_PIECE_SOUTH, + BRIDGE_PIECE_INNER_NORTH, + BRIDGE_PIECE_INNER_SOUTH, + BRIDGE_PIECE_MIDDLE_ODD, + BRIDGE_PIECE_MIDDLE_EVEN, + BRIDGE_PIECE_HEAD, + BRIDGE_PIECE_INVALID, +}; + +DECLARE_POSTFIX_INCREMENT(BridgePieces) + +static const uint MAX_BRIDGES = 13; ///< Maximal number of available bridge specs. + +typedef uint BridgeType; ///< Bridge spec number. + +/** + * Struct containing information about a single bridge type + */ +struct BridgeSpec { + Year avail_year; ///< the year where it becomes available + byte min_length; ///< the minimum length (not counting start and end tile) + uint16 max_length; ///< the maximum length (not counting start and end tile) + uint16 price; ///< the price multiplier + uint16 speed; ///< maximum travel speed (1 unit = 1/1.6 mph = 1 km-ish/h) + SpriteID sprite; ///< the sprite which is used in the GUI + PaletteID pal; ///< the palette which is used in the GUI + StringID material; ///< the string that contains the bridge description + StringID transport_name[2]; ///< description of the bridge, when built for road or rail + PalSpriteID **sprite_table; ///< table of sprites for drawing the bridge + byte flags; ///< bit 0 set: disable drawing of far pillars. +}; + +extern BridgeSpec _bridge[MAX_BRIDGES]; + +Foundation GetBridgeFoundation(Slope tileh, Axis axis); +bool HasBridgeFlatRamp(Slope tileh, Axis axis); + +/** + * Get the specification of a bridge type. + * @param i The type of bridge to get the specification for. + * @return The specification. + */ +static inline const BridgeSpec *GetBridgeSpec(BridgeType i) +{ + assert(i < lengthof(_bridge)); + return &_bridge[i]; +} + +void DrawBridgeMiddle(const TileInfo *ti); + +CommandCost CheckBridgeAvailability(BridgeType bridge_type, uint bridge_len, DoCommandFlag flags = DC_NONE); +int CalcBridgeLenCostFactor(int x); + +void ResetBridges(); + +#endif /* BRIDGE_H */ diff --git a/src/bridge_gui.cpp b/src/bridge_gui.cpp new file mode 100644 index 0000000..797ead1 --- /dev/null +++ b/src/bridge_gui.cpp @@ -0,0 +1,435 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file bridge_gui.cpp Graphical user interface for bridge construction */ + +#include "stdafx.h" +#include "error.h" +#include "command_func.h" +#include "rail.h" +#include "strings_func.h" +#include "window_func.h" +#include "sound_func.h" +#include "gfx_func.h" +#include "tunnelbridge.h" +#include "sortlist_type.h" +#include "widgets/dropdown_func.h" +#include "core/geometry_func.hpp" +#include "cmd_helper.h" +#include "tunnelbridge_map.h" +#include "road_gui.h" + +#include "widgets/bridge_widget.h" + +#include "table/strings.h" + +#include "safeguards.h" + +/** The type of the last built rail bridge */ +static BridgeType _last_railbridge_type = 0; +/** The type of the last built road bridge */ +static BridgeType _last_roadbridge_type = 0; + +/** + * Carriage for the data we need if we want to build a bridge + */ +struct BuildBridgeData { + BridgeType index; + const BridgeSpec *spec; + Money cost; +}; + +typedef GUIList GUIBridgeList; ///< List of bridges, used in #BuildBridgeWindow. + +/** + * Callback executed after a build Bridge CMD has been called + * + * @param result Whether the build succeeded + * @param end_tile End tile of the bridge. + * @param p1 packed start tile coords (~ dx) + * @param p2 various bitstuffed elements + * - p2 = (bit 0- 7) - bridge type (hi bh) + * - p2 = (bit 8-11) - rail type or road types. + * - p2 = (bit 15-16) - transport type. + */ +void CcBuildBridge(const CommandCost &result, TileIndex end_tile, uint32 p1, uint32 p2) +{ + if (result.Failed()) return; + if (_settings_client.sound.confirm) SndPlayTileFx(SND_27_BLACKSMITH_ANVIL, end_tile); + + TransportType transport_type = Extract(p2); + + if (transport_type == TRANSPORT_ROAD) { + DiagDirection end_direction = ReverseDiagDir(GetTunnelBridgeDirection(end_tile)); + ConnectRoadToStructure(end_tile, end_direction); + + DiagDirection start_direction = ReverseDiagDir(GetTunnelBridgeDirection(p1)); + ConnectRoadToStructure(p1, start_direction); + } +} + +/** Window class for handling the bridge-build GUI. */ +class BuildBridgeWindow : public Window { +private: + /* Runtime saved values */ + static Listing last_sorting; ///< Last setting of the sort. + + /* Constants for sorting the bridges */ + static const StringID sorter_names[]; + static GUIBridgeList::SortFunction * const sorter_funcs[]; + + /* Internal variables */ + TileIndex start_tile; + TileIndex end_tile; + uint32 type; + GUIBridgeList *bridges; + int bridgetext_offset; ///< Horizontal offset of the text describing the bridge properties in #WID_BBS_BRIDGE_LIST relative to the left edge. + Scrollbar *vscroll; + + /** Sort the bridges by their index */ + static int CDECL BridgeIndexSorter(const BuildBridgeData *a, const BuildBridgeData *b) + { + return a->index - b->index; + } + + /** Sort the bridges by their price */ + static int CDECL BridgePriceSorter(const BuildBridgeData *a, const BuildBridgeData *b) + { + return a->cost - b->cost; + } + + /** Sort the bridges by their maximum speed */ + static int CDECL BridgeSpeedSorter(const BuildBridgeData *a, const BuildBridgeData *b) + { + return a->spec->speed - b->spec->speed; + } + + void BuildBridge(uint8 i) + { + switch ((TransportType)(this->type >> 15)) { + case TRANSPORT_RAIL: _last_railbridge_type = this->bridges->Get(i)->index; break; + case TRANSPORT_ROAD: _last_roadbridge_type = this->bridges->Get(i)->index; break; + default: break; + } + DoCommandP(this->end_tile, this->start_tile, this->type | this->bridges->Get(i)->index, + CMD_BUILD_BRIDGE | CMD_MSG(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE), CcBuildBridge); + } + + /** Sort the builable bridges */ + void SortBridgeList() + { + this->bridges->Sort(); + + /* Display the current sort variant */ + this->GetWidget(WID_BBS_DROPDOWN_CRITERIA)->widget_data = this->sorter_names[this->bridges->SortType()]; + + /* Set the modified widgets dirty */ + this->SetWidgetDirty(WID_BBS_DROPDOWN_CRITERIA); + this->SetWidgetDirty(WID_BBS_BRIDGE_LIST); + } + +public: + BuildBridgeWindow(WindowDesc *desc, TileIndex start, TileIndex end, uint32 br_type, GUIBridgeList *bl) : Window(desc), + start_tile(start), + end_tile(end), + type(br_type), + bridges(bl) + { + this->CreateNestedTree(); + this->vscroll = this->GetScrollbar(WID_BBS_SCROLLBAR); + /* Change the data, or the caption of the gui. Set it to road or rail, accordingly. */ + this->GetWidget(WID_BBS_CAPTION)->widget_data = (GB(this->type, 15, 2) == TRANSPORT_ROAD) ? STR_SELECT_ROAD_BRIDGE_CAPTION : STR_SELECT_RAIL_BRIDGE_CAPTION; + this->FinishInitNested(GB(br_type, 15, 2)); // Initializes 'this->bridgetext_offset'. + + this->parent = FindWindowById(WC_BUILD_TOOLBAR, GB(this->type, 15, 2)); + this->bridges->SetListing(this->last_sorting); + this->bridges->SetSortFuncs(this->sorter_funcs); + this->bridges->NeedResort(); + this->SortBridgeList(); + + this->vscroll->SetCount(bl->Length()); + } + + ~BuildBridgeWindow() + { + this->last_sorting = this->bridges->GetListing(); + + delete bridges; + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_BBS_DROPDOWN_ORDER: { + Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); + d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better. + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + case WID_BBS_DROPDOWN_CRITERIA: { + Dimension d = {0, 0}; + for (const StringID *str = this->sorter_names; *str != INVALID_STRING_ID; str++) { + d = maxdim(d, GetStringBoundingBox(*str)); + } + d.width += padding.width; + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + case WID_BBS_BRIDGE_LIST: { + Dimension sprite_dim = {0, 0}; // Biggest bridge sprite dimension + Dimension text_dim = {0, 0}; // Biggest text dimension + for (int i = 0; i < (int)this->bridges->Length(); i++) { + const BridgeSpec *b = this->bridges->Get(i)->spec; + sprite_dim = maxdim(sprite_dim, GetSpriteSize(b->sprite)); + + SetDParam(2, this->bridges->Get(i)->cost); + SetDParam(1, b->speed); + SetDParam(0, b->material); + text_dim = maxdim(text_dim, GetStringBoundingBox(_game_mode == GM_EDITOR ? STR_SELECT_BRIDGE_SCENEDIT_INFO : STR_SELECT_BRIDGE_INFO)); + } + sprite_dim.height++; // Sprite is rendered one pixel down in the matrix field. + text_dim.height++; // Allowing the bottom row pixels to be rendered on the edge of the matrix field. + resize->height = max(sprite_dim.height, text_dim.height) + 2; // Max of both sizes + account for matrix edges. + + this->bridgetext_offset = WD_MATRIX_LEFT + sprite_dim.width + 1; // Left edge of text, 1 pixel distance from the sprite. + size->width = this->bridgetext_offset + text_dim.width + WD_MATRIX_RIGHT; + size->height = 4 * resize->height; // Smallest bridge gui is 4 entries high in the matrix. + break; + } + } + } + + virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) + { + /* Position the window so hopefully the first bridge from the list is under the mouse pointer. */ + NWidgetBase *list = this->GetWidget(WID_BBS_BRIDGE_LIST); + Point corner; // point of the top left corner of the window. + corner.y = Clamp(_cursor.pos.y - list->pos_y - 5, GetMainViewTop(), GetMainViewBottom() - sm_height); + corner.x = Clamp(_cursor.pos.x - list->pos_x - 5, 0, _screen.width - sm_width); + return corner; + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_BBS_DROPDOWN_ORDER: + this->DrawSortButtonState(widget, this->bridges->IsDescSortOrder() ? SBS_DOWN : SBS_UP); + break; + + case WID_BBS_BRIDGE_LIST: { + uint y = r.top; + for (int i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < (int)this->bridges->Length(); i++) { + const BridgeSpec *b = this->bridges->Get(i)->spec; + + SetDParam(2, this->bridges->Get(i)->cost); + SetDParam(1, b->speed); + SetDParam(0, b->material); + + DrawSprite(b->sprite, b->pal, r.left + WD_MATRIX_LEFT, y + this->resize.step_height - 1 - GetSpriteSize(b->sprite).height); + DrawStringMultiLine(r.left + this->bridgetext_offset, r.right, y + 2, y + this->resize.step_height, + _game_mode == GM_EDITOR ? STR_SELECT_BRIDGE_SCENEDIT_INFO : STR_SELECT_BRIDGE_INFO); + y += this->resize.step_height; + } + break; + } + } + } + + virtual EventState OnKeyPress(WChar key, uint16 keycode) + { + const uint8 i = keycode - '1'; + if (i < 9 && i < this->bridges->Length()) { + /* Build the requested bridge */ + this->BuildBridge(i); + delete this; + return ES_HANDLED; + } + return ES_NOT_HANDLED; + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + default: break; + case WID_BBS_BRIDGE_LIST: { + uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BBS_BRIDGE_LIST); + if (i < this->bridges->Length()) { + this->BuildBridge(i); + delete this; + } + break; + } + + case WID_BBS_DROPDOWN_ORDER: + this->bridges->ToggleSortOrder(); + this->SetDirty(); + break; + + case WID_BBS_DROPDOWN_CRITERIA: + ShowDropDownMenu(this, this->sorter_names, this->bridges->SortType(), WID_BBS_DROPDOWN_CRITERIA, 0, 0); + break; + } + } + + virtual void OnDropdownSelect(int widget, int index) + { + if (widget == WID_BBS_DROPDOWN_CRITERIA && this->bridges->SortType() != index) { + this->bridges->SetSortType(index); + + this->SortBridgeList(); + } + } + + virtual void OnResize() + { + this->vscroll->SetCapacityFromWidget(this, WID_BBS_BRIDGE_LIST); + } +}; + +/** Set the default sorting for the bridges */ +Listing BuildBridgeWindow::last_sorting = {true, 2}; + +/** Available bridge sorting functions. */ +GUIBridgeList::SortFunction * const BuildBridgeWindow::sorter_funcs[] = { + &BridgeIndexSorter, + &BridgePriceSorter, + &BridgeSpeedSorter +}; + +/** Names of the sorting functions. */ +const StringID BuildBridgeWindow::sorter_names[] = { + STR_SORT_BY_NUMBER, + STR_SORT_BY_COST, + STR_SORT_BY_MAX_SPEED, + INVALID_STRING_ID +}; + +/** Widgets of the bridge gui. */ +static const NWidgetPart _nested_build_bridge_widgets[] = { + /* Header */ + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_BBS_CAPTION), SetDataTip(STR_SELECT_RAIL_BRIDGE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN), + EndContainer(), + + NWidget(NWID_HORIZONTAL), + NWidget(NWID_VERTICAL), + /* Sort order + criteria buttons */ + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXTBTN, COLOUR_DARK_GREEN, WID_BBS_DROPDOWN_ORDER), SetFill(1, 0), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), + NWidget(WWT_DROPDOWN, COLOUR_DARK_GREEN, WID_BBS_DROPDOWN_CRITERIA), SetFill(1, 0), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA), + EndContainer(), + /* Matrix. */ + NWidget(WWT_MATRIX, COLOUR_DARK_GREEN, WID_BBS_BRIDGE_LIST), SetFill(1, 0), SetResize(0, 22), SetMatrixDataTip(1, 0, STR_SELECT_BRIDGE_SELECTION_TOOLTIP), SetScrollbar(WID_BBS_SCROLLBAR), + EndContainer(), + + /* scrollbar + resize button */ + NWidget(NWID_VERTICAL), + NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_BBS_SCROLLBAR), + NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN), + EndContainer(), + EndContainer(), +}; + +/** Window definition for the rail bridge selection window. */ +static WindowDesc _build_bridge_desc( + WDP_AUTO, "build_bridge", 200, 114, + WC_BUILD_BRIDGE, WC_BUILD_TOOLBAR, + WDF_CONSTRUCTION, + _nested_build_bridge_widgets, lengthof(_nested_build_bridge_widgets) +); + +/** + * Prepare the data for the build a bridge window. + * If we can't build a bridge under the given conditions + * show an error message. + * + * @param start The start tile of the bridge + * @param end The end tile of the bridge + * @param transport_type The transport type + * @param road_rail_type The road/rail type + */ +void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transport_type, byte road_rail_type) +{ + DeleteWindowByClass(WC_BUILD_BRIDGE); + + /* Data type for the bridge. + * Bit 16,15 = transport type, + * 14..8 = road/rail types, + * 7..0 = type of bridge */ + uint32 type = (transport_type << 15) | (road_rail_type << 8); + + /* The bridge length without ramps. */ + const uint bridge_len = GetTunnelBridgeLength(start, end); + + /* If Ctrl is being pressed, check whether the last bridge built is available + * If so, return this bridge type. Otherwise continue normally. + * We store bridge types for each transport type, so we have to check for + * the transport type beforehand. + */ + BridgeType last_bridge_type = 0; + switch (transport_type) { + case TRANSPORT_ROAD: last_bridge_type = _last_roadbridge_type; break; + case TRANSPORT_RAIL: last_bridge_type = _last_railbridge_type; break; + default: break; // water ways and air routes don't have bridge types + } + if (_ctrl_pressed && CheckBridgeAvailability(last_bridge_type, bridge_len).Succeeded()) { + DoCommandP(end, start, type | last_bridge_type, CMD_BUILD_BRIDGE | CMD_MSG(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE), CcBuildBridge); + return; + } + + /* only query bridge building possibility once, result is the same for all bridges! + * returns CMD_ERROR on failure, and price on success */ + StringID errmsg = INVALID_STRING_ID; + CommandCost ret = DoCommand(end, start, type, CommandFlagsToDCFlags(GetCommandFlags(CMD_BUILD_BRIDGE)) | DC_QUERY_COST, CMD_BUILD_BRIDGE); + + GUIBridgeList *bl = NULL; + if (ret.Failed()) { + errmsg = ret.GetErrorMessage(); + } else { + /* check which bridges can be built */ + const uint tot_bridgedata_len = CalcBridgeLenCostFactor(bridge_len + 2); + + bl = new GUIBridgeList(); + + Money infra_cost = 0; + switch (transport_type) { + case TRANSPORT_ROAD: + infra_cost = (bridge_len + 2) * _price[PR_BUILD_ROAD] * 2; + /* In case we add a new road type as well, we must be aware of those costs. */ + if (IsBridgeTile(start)) infra_cost *= CountBits(GetRoadTypes(start) | (RoadTypes)road_rail_type); + break; + case TRANSPORT_RAIL: infra_cost = (bridge_len + 2) * RailBuildCost((RailType)road_rail_type); break; + default: break; + } + + /* loop for all bridgetypes */ + for (BridgeType brd_type = 0; brd_type != MAX_BRIDGES; brd_type++) { + if (CheckBridgeAvailability(brd_type, bridge_len).Succeeded()) { + /* bridge is accepted, add to list */ + BuildBridgeData *item = bl->Append(); + item->index = brd_type; + item->spec = GetBridgeSpec(brd_type); + /* Add to terraforming & bulldozing costs the cost of the + * bridge itself (not computed with DC_QUERY_COST) */ + item->cost = ret.GetCost() + (((int64)tot_bridgedata_len * _price[PR_BUILD_BRIDGE] * item->spec->price) >> 8) + infra_cost; + } + } + } + + if (bl != NULL && bl->Length() != 0) { + new BuildBridgeWindow(&_build_bridge_desc, start, end, type, bl); + } else { + delete bl; + ShowErrorMessage(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE, errmsg, WL_INFO, TileX(end) * TILE_SIZE, TileY(end) * TILE_SIZE); + } +} diff --git a/src/bridge_map.cpp b/src/bridge_map.cpp new file mode 100644 index 0000000..d1e0d60 --- /dev/null +++ b/src/bridge_map.cpp @@ -0,0 +1,80 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file bridge_map.cpp Map accessor functions for bridges. */ + +#include "stdafx.h" +#include "landscape.h" +#include "tunnelbridge_map.h" + +#include "safeguards.h" + + +/** + * Finds the end of a bridge in the specified direction starting at a middle tile + * @param tile the bridge tile to find the bridge ramp for + * @param dir the direction to search in + */ +static TileIndex GetBridgeEnd(TileIndex tile, DiagDirection dir) +{ + TileIndexDiff delta = TileOffsByDiagDir(dir); + + dir = ReverseDiagDir(dir); + do { + tile += delta; + } while (!IsBridgeTile(tile) || GetTunnelBridgeDirection(tile) != dir); + + return tile; +} + + +/** + * Finds the northern end of a bridge starting at a middle tile + * @param t the bridge tile to find the bridge ramp for + */ +TileIndex GetNorthernBridgeEnd(TileIndex t) +{ + return GetBridgeEnd(t, ReverseDiagDir(AxisToDiagDir(GetBridgeAxis(t)))); +} + + +/** + * Finds the southern end of a bridge starting at a middle tile + * @param t the bridge tile to find the bridge ramp for + */ +TileIndex GetSouthernBridgeEnd(TileIndex t) +{ + return GetBridgeEnd(t, AxisToDiagDir(GetBridgeAxis(t))); +} + + +/** + * Starting at one bridge end finds the other bridge end + * @param t the bridge ramp tile to find the other bridge ramp for + */ +TileIndex GetOtherBridgeEnd(TileIndex tile) +{ + assert(IsBridgeTile(tile)); + return GetBridgeEnd(tile, GetTunnelBridgeDirection(tile)); +} + +/** + * Get the height ('z') of a bridge. + * @param tile the bridge ramp tile to get the bridge height from + * @return the height of the bridge. + */ +int GetBridgeHeight(TileIndex t) +{ + int h; + Slope tileh = GetTileSlope(t, &h); + Foundation f = GetBridgeFoundation(tileh, DiagDirToAxis(GetTunnelBridgeDirection(t))); + + /* one height level extra for the ramp */ + return h + 1 + ApplyFoundationToSlope(f, &tileh); +} diff --git a/src/bridge_map.h b/src/bridge_map.h new file mode 100644 index 0000000..74c6974 --- /dev/null +++ b/src/bridge_map.h @@ -0,0 +1,183 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file bridge_map.h Map accessor functions for bridges. */ + +#ifndef BRIDGE_MAP_H +#define BRIDGE_MAP_H + +#include "road_map.h" +#include "bridge.h" + +/** + * Checks if this is a bridge, instead of a tunnel + * @param t The tile to analyze + * @pre IsTileType(t, MP_TUNNELBRIDGE) + * @return true if the structure is a bridge one + */ +static inline bool IsBridge(TileIndex t) +{ + assert(IsTileType(t, MP_TUNNELBRIDGE)); + return HasBit(_m[t].m5, 7); +} + +/** + * checks if there is a bridge on this tile + * @param t The tile to analyze + * @return true if a bridge is present + */ +static inline bool IsBridgeTile(TileIndex t) +{ + return IsTileType(t, MP_TUNNELBRIDGE) && IsBridge(t); +} + +/** + * checks if a bridge is set above the ground of this tile + * @param t The tile to analyze + * @return true if a bridge is detected above + */ +static inline bool IsBridgeAbove(TileIndex t) +{ + return GB(_m[t].type, 2, 2) != 0; +} + +/** + * Determines the type of bridge on a tile + * @param t The tile to analyze + * @pre IsBridgeTile(t) + * @return The bridge type + */ +static inline BridgeType GetBridgeType(TileIndex t) +{ + assert(IsBridgeTile(t)); + return GB(_me[t].m6, 2, 4); +} + +/** + * Get the axis of the bridge that goes over the tile. Not the axis or the ramp. + * @param t The tile to analyze + * @pre IsBridgeAbove(t) + * @return the above mentioned axis + */ +static inline Axis GetBridgeAxis(TileIndex t) +{ + assert(IsBridgeAbove(t)); + return (Axis)(GB(_m[t].type, 2, 2) - 1); +} + +TileIndex GetNorthernBridgeEnd(TileIndex t); +TileIndex GetSouthernBridgeEnd(TileIndex t); +TileIndex GetOtherBridgeEnd(TileIndex t); + +int GetBridgeHeight(TileIndex tile); +/** + * Get the height ('z') of a bridge in pixels. + * @param tile the bridge ramp tile to get the bridge height from + * @return the height of the bridge in pixels + */ +static inline int GetBridgePixelHeight(TileIndex tile) +{ + return GetBridgeHeight(tile) * TILE_HEIGHT; +} + +/** + * Remove the bridge over the given axis. + * @param t the tile to remove the bridge from + * @param a the axis of the bridge to remove + */ +static inline void ClearSingleBridgeMiddle(TileIndex t, Axis a) +{ + ClrBit(_m[t].type, 2 + a); +} + +/** + * Removes bridges from the given, that is bridges along the X and Y axis. + * @param t the tile to remove the bridge from + */ +static inline void ClearBridgeMiddle(TileIndex t) +{ + ClearSingleBridgeMiddle(t, AXIS_X); + ClearSingleBridgeMiddle(t, AXIS_Y); +} + +/** + * Set that there is a bridge over the given axis. + * @param t the tile to add the bridge to + * @param a the axis of the bridge to add + */ +static inline void SetBridgeMiddle(TileIndex t, Axis a) +{ + SetBit(_m[t].type, 2 + a); +} + +/** + * Generic part to make a bridge ramp for both roads and rails. + * @param t the tile to make a bridge ramp + * @param o the new owner of the bridge ramp + * @param bridgetype the type of bridge this bridge ramp belongs to + * @param d the direction this ramp must be facing + * @param tt the transport type of the bridge + * @param rt the road or rail type + * @note this function should not be called directly. + */ +static inline void MakeBridgeRamp(TileIndex t, Owner o, BridgeType bridgetype, DiagDirection d, TransportType tt, uint rt) +{ + SetTileType(t, MP_TUNNELBRIDGE); + SetTileOwner(t, o); + _m[t].m2 = 0; + _m[t].m3 = rt; + _m[t].m4 = 0; + _m[t].m5 = 1 << 7 | tt << 2 | d; + SB(_me[t].m6, 2, 4, bridgetype); + _me[t].m7 = 0; +} + +/** + * Make a bridge ramp for roads. + * @param t the tile to make a bridge ramp + * @param o the new owner of the bridge ramp + * @param owner_road the new owner of the road on the bridge + * @param owner_tram the new owner of the tram on the bridge + * @param bridgetype the type of bridge this bridge ramp belongs to + * @param d the direction this ramp must be facing + * @param r the road type of the bridge + */ +static inline void MakeRoadBridgeRamp(TileIndex t, Owner o, Owner owner_road, Owner owner_tram, BridgeType bridgetype, DiagDirection d, RoadTypes r) +{ + MakeBridgeRamp(t, o, bridgetype, d, TRANSPORT_ROAD, 0); + SetRoadOwner(t, ROADTYPE_ROAD, owner_road); + if (owner_tram != OWNER_TOWN) SetRoadOwner(t, ROADTYPE_TRAM, owner_tram); + SetRoadTypes(t, r); +} + +/** + * Make a bridge ramp for rails. + * @param t the tile to make a bridge ramp + * @param o the new owner of the bridge ramp + * @param bridgetype the type of bridge this bridge ramp belongs to + * @param d the direction this ramp must be facing + * @param r the rail type of the bridge + */ +static inline void MakeRailBridgeRamp(TileIndex t, Owner o, BridgeType bridgetype, DiagDirection d, RailType r) +{ + MakeBridgeRamp(t, o, bridgetype, d, TRANSPORT_RAIL, r); +} + +/** + * Make a bridge ramp for aqueducts. + * @param t the tile to make a bridge ramp + * @param o the new owner of the bridge ramp + * @param d the direction this ramp must be facing + */ +static inline void MakeAqueductBridgeRamp(TileIndex t, Owner o, DiagDirection d) +{ + MakeBridgeRamp(t, o, 0, d, TRANSPORT_WATER, 0); +} + +#endif /* BRIDGE_MAP_H */ diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp new file mode 100644 index 0000000..bd4bf3b --- /dev/null +++ b/src/build_vehicle_gui.cpp @@ -0,0 +1,1506 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file build_vehicle_gui.cpp GUI for building vehicles. */ + +#include "stdafx.h" +#include "engine_base.h" +#include "engine_func.h" +#include "station_base.h" +#include "network/network.h" +#include "articulated_vehicles.h" +#include "textbuf_gui.h" +#include "command_func.h" +#include "company_func.h" +#include "vehicle_gui.h" +#include "newgrf_engine.h" +#include "newgrf_text.h" +#include "group.h" +#include "string_func.h" +#include "strings_func.h" +#include "window_func.h" +#include "date_func.h" +#include "vehicle_func.h" +#include "widgets/dropdown_func.h" +#include "engine_gui.h" +#include "cargotype.h" +#include "core/geometry_func.hpp" +#include "autoreplace_func.h" + +#include "widgets/build_vehicle_widget.h" + +#include "table/strings.h" + +#include "safeguards.h" + +/** + * Get the height of a single 'entry' in the engine lists. + * @param type the vehicle type to get the height of + * @return the height for the entry + */ +uint GetEngineListHeight(VehicleType type) +{ + return max(FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM, GetVehicleImageCellSize(type, EIT_PURCHASE).height); +} + +static const NWidgetPart _nested_build_vehicle_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_BV_CAPTION), SetDataTip(STR_WHITE_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), + NWidget(WWT_STICKYBOX, COLOUR_GREY), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), + NWidget(NWID_VERTICAL), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_SORT_ASCENDING_DESCENDING), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_SORT_DROPDOWN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BV_SHOW_HIDDEN_ENGINES), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_CARGO_FILTER_DROPDOWN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_FILTER_CRITERIA), + EndContainer(), + EndContainer(), + EndContainer(), + /* Vehicle list. */ + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_BV_LIST), SetResize(1, 1), SetFill(1, 0), SetMatrixDataTip(1, 0, STR_NULL), SetScrollbar(WID_BV_SCROLLBAR), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_BV_SCROLLBAR), + EndContainer(), + /* Panel with details. */ + NWidget(WWT_PANEL, COLOUR_GREY, WID_BV_PANEL), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(), + /* Build/rename buttons, resize button. */ + NWidget(NWID_HORIZONTAL), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BV_BUILD_SEL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_BUILD), SetResize(1, 0), SetFill(1, 0), + EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_SHOW_HIDE), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_RENAME), SetResize(1, 0), SetFill(1, 0), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), +}; + +/** Special cargo filter criteria */ +static const CargoID CF_ANY = CT_NO_REFIT; ///< Show all vehicles independent of carried cargo (i.e. no filtering) +static const CargoID CF_NONE = CT_INVALID; ///< Show only vehicles which do not carry cargo (e.g. train engines) + +bool _engine_sort_direction; ///< \c false = descending, \c true = ascending. +byte _engine_sort_last_criteria[] = {0, 0, 0, 0}; ///< Last set sort criteria, for each vehicle type. +bool _engine_sort_last_order[] = {false, false, false, false}; ///< Last set direction of the sort order, for each vehicle type. +bool _engine_sort_show_hidden_engines[] = {false, false, false, false}; ///< Last set 'show hidden engines' setting for each vehicle type. +static CargoID _engine_sort_last_cargo_criteria[] = {CF_ANY, CF_ANY, CF_ANY, CF_ANY}; ///< Last set filter criteria, for each vehicle type. + +/** + * Determines order of engines by engineID + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EngineNumberSorter(const EngineID *a, const EngineID *b) +{ + int r = Engine::Get(*a)->list_position - Engine::Get(*b)->list_position; + + return _engine_sort_direction ? -r : r; +} + +/** + * Determines order of engines by introduction date + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EngineIntroDateSorter(const EngineID *a, const EngineID *b) +{ + const int va = Engine::Get(*a)->intro_date; + const int vb = Engine::Get(*b)->intro_date; + const int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _engine_sort_direction ? -r : r; +} + +/** + * Determines order of engines by name + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EngineNameSorter(const EngineID *a, const EngineID *b) +{ + static EngineID last_engine[2] = { INVALID_ENGINE, INVALID_ENGINE }; + static char last_name[2][64] = { "\0", "\0" }; + + const EngineID va = *a; + const EngineID vb = *b; + + if (va != last_engine[0]) { + last_engine[0] = va; + SetDParam(0, va); + GetString(last_name[0], STR_ENGINE_NAME, lastof(last_name[0])); + } + + if (vb != last_engine[1]) { + last_engine[1] = vb; + SetDParam(0, vb); + GetString(last_name[1], STR_ENGINE_NAME, lastof(last_name[1])); + } + + int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting). + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _engine_sort_direction ? -r : r; +} + +/** + * Determines order of engines by reliability + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EngineReliabilitySorter(const EngineID *a, const EngineID *b) +{ + const int va = Engine::Get(*a)->reliability; + const int vb = Engine::Get(*b)->reliability; + const int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _engine_sort_direction ? -r : r; +} + +/** + * Determines order of engines by purchase cost + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EngineCostSorter(const EngineID *a, const EngineID *b) +{ + Money va = Engine::Get(*a)->GetCost(); + Money vb = Engine::Get(*b)->GetCost(); + int r = ClampToI32(va - vb); + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _engine_sort_direction ? -r : r; +} + +/** + * Determines order of engines by speed + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EngineSpeedSorter(const EngineID *a, const EngineID *b) +{ + int va = Engine::Get(*a)->GetDisplayMaxSpeed(); + int vb = Engine::Get(*b)->GetDisplayMaxSpeed(); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _engine_sort_direction ? -r : r; +} + +/** + * Determines order of engines by power + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EnginePowerSorter(const EngineID *a, const EngineID *b) +{ + int va = Engine::Get(*a)->GetPower(); + int vb = Engine::Get(*b)->GetPower(); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _engine_sort_direction ? -r : r; +} + +/** + * Determines order of engines by tractive effort + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EngineTractiveEffortSorter(const EngineID *a, const EngineID *b) +{ + int va = Engine::Get(*a)->GetDisplayMaxTractiveEffort(); + int vb = Engine::Get(*b)->GetDisplayMaxTractiveEffort(); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _engine_sort_direction ? -r : r; +} + +/** + * Determines order of engines by running costs + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EngineRunningCostSorter(const EngineID *a, const EngineID *b) +{ + Money va = Engine::Get(*a)->GetRunningCost(); + Money vb = Engine::Get(*b)->GetRunningCost(); + int r = ClampToI32(va - vb); + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _engine_sort_direction ? -r : r; +} + +/** + * Determines order of engines by running costs + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL EnginePowerVsRunningCostSorter(const EngineID *a, const EngineID *b) +{ + const Engine *e_a = Engine::Get(*a); + const Engine *e_b = Engine::Get(*b); + + /* Here we are using a few tricks to get the right sort. + * We want power/running cost, but since we usually got higher running cost than power and we store the result in an int, + * we will actually calculate cunning cost/power (to make it more than 1). + * Because of this, the return value have to be reversed as well and we return b - a instead of a - b. + * Another thing is that both power and running costs should be doubled for multiheaded engines. + * Since it would be multiplying with 2 in both numerator and denominator, it will even themselves out and we skip checking for multiheaded. */ + Money va = (e_a->GetRunningCost()) / max(1U, (uint)e_a->GetPower()); + Money vb = (e_b->GetRunningCost()) / max(1U, (uint)e_b->GetPower()); + int r = ClampToI32(vb - va); + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _engine_sort_direction ? -r : r; +} + +/* Train sorting functions */ + +/** + * Determines order of train engines by capacity + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL TrainEngineCapacitySorter(const EngineID *a, const EngineID *b) +{ + const RailVehicleInfo *rvi_a = RailVehInfo(*a); + const RailVehicleInfo *rvi_b = RailVehInfo(*b); + + int va = GetTotalCapacityOfArticulatedParts(*a) * (rvi_a->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1); + int vb = GetTotalCapacityOfArticulatedParts(*b) * (rvi_b->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _engine_sort_direction ? -r : r; +} + +/** + * Determines order of train engines by engine / wagon + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL TrainEnginesThenWagonsSorter(const EngineID *a, const EngineID *b) +{ + int val_a = (RailVehInfo(*a)->railveh_type == RAILVEH_WAGON ? 1 : 0); + int val_b = (RailVehInfo(*b)->railveh_type == RAILVEH_WAGON ? 1 : 0); + int r = val_a - val_b; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _engine_sort_direction ? -r : r; +} + +/* Road vehicle sorting functions */ + +/** + * Determines order of road vehicles by capacity + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL RoadVehEngineCapacitySorter(const EngineID *a, const EngineID *b) +{ + int va = GetTotalCapacityOfArticulatedParts(*a); + int vb = GetTotalCapacityOfArticulatedParts(*b); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _engine_sort_direction ? -r : r; +} + +/* Ship vehicle sorting functions */ + +/** + * Determines order of ships by capacity + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL ShipEngineCapacitySorter(const EngineID *a, const EngineID *b) +{ + const Engine *e_a = Engine::Get(*a); + const Engine *e_b = Engine::Get(*b); + + int va = e_a->GetDisplayDefaultCapacity(); + int vb = e_b->GetDisplayDefaultCapacity(); + int r = va - vb; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _engine_sort_direction ? -r : r; +} + +/* Aircraft sorting functions */ + +/** + * Determines order of aircraft by cargo + * @param *a first engine to compare + * @param *b second engine to compare + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal + */ +static int CDECL AircraftEngineCargoSorter(const EngineID *a, const EngineID *b) +{ + const Engine *e_a = Engine::Get(*a); + const Engine *e_b = Engine::Get(*b); + + uint16 mail_a, mail_b; + int va = e_a->GetDisplayDefaultCapacity(&mail_a); + int vb = e_b->GetDisplayDefaultCapacity(&mail_b); + int r = va - vb; + + if (r == 0) { + /* The planes have the same passenger capacity. Check mail capacity instead */ + r = mail_a - mail_b; + + if (r == 0) { + /* Use EngineID to sort instead since we want consistent sorting */ + return EngineNumberSorter(a, b); + } + } + return _engine_sort_direction ? -r : r; +} + +/** + * Determines order of aircraft by range. + * @param *a first engine to compare. + * @param *b second engine to compare. + * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal. + */ +static int CDECL AircraftRangeSorter(const EngineID *a, const EngineID *b) +{ + uint16 r_a = Engine::Get(*a)->GetRange(); + uint16 r_b = Engine::Get(*b)->GetRange(); + + int r = r_a - r_b; + + /* Use EngineID to sort instead since we want consistent sorting */ + if (r == 0) return EngineNumberSorter(a, b); + return _engine_sort_direction ? -r : r; +} + +/** Sort functions for the vehicle sort criteria, for each vehicle type. */ +EngList_SortTypeFunction * const _engine_sort_functions[][11] = {{ + /* Trains */ + &EngineNumberSorter, + &EngineCostSorter, + &EngineSpeedSorter, + &EnginePowerSorter, + &EngineTractiveEffortSorter, + &EngineIntroDateSorter, + &EngineNameSorter, + &EngineRunningCostSorter, + &EnginePowerVsRunningCostSorter, + &EngineReliabilitySorter, + &TrainEngineCapacitySorter, +}, { + /* Road vehicles */ + &EngineNumberSorter, + &EngineCostSorter, + &EngineSpeedSorter, + &EnginePowerSorter, + &EngineTractiveEffortSorter, + &EngineIntroDateSorter, + &EngineNameSorter, + &EngineRunningCostSorter, + &EnginePowerVsRunningCostSorter, + &EngineReliabilitySorter, + &RoadVehEngineCapacitySorter, +}, { + /* Ships */ + &EngineNumberSorter, + &EngineCostSorter, + &EngineSpeedSorter, + &EngineIntroDateSorter, + &EngineNameSorter, + &EngineRunningCostSorter, + &EngineReliabilitySorter, + &ShipEngineCapacitySorter, +}, { + /* Aircraft */ + &EngineNumberSorter, + &EngineCostSorter, + &EngineSpeedSorter, + &EngineIntroDateSorter, + &EngineNameSorter, + &EngineRunningCostSorter, + &EngineReliabilitySorter, + &AircraftEngineCargoSorter, + &AircraftRangeSorter, +}}; + +/** Dropdown menu strings for the vehicle sort criteria. */ +const StringID _engine_sort_listing[][12] = {{ + /* Trains */ + STR_SORT_BY_ENGINE_ID, + STR_SORT_BY_COST, + STR_SORT_BY_MAX_SPEED, + STR_SORT_BY_POWER, + STR_SORT_BY_TRACTIVE_EFFORT, + STR_SORT_BY_INTRO_DATE, + STR_SORT_BY_NAME, + STR_SORT_BY_RUNNING_COST, + STR_SORT_BY_POWER_VS_RUNNING_COST, + STR_SORT_BY_RELIABILITY, + STR_SORT_BY_CARGO_CAPACITY, + INVALID_STRING_ID +}, { + /* Road vehicles */ + STR_SORT_BY_ENGINE_ID, + STR_SORT_BY_COST, + STR_SORT_BY_MAX_SPEED, + STR_SORT_BY_POWER, + STR_SORT_BY_TRACTIVE_EFFORT, + STR_SORT_BY_INTRO_DATE, + STR_SORT_BY_NAME, + STR_SORT_BY_RUNNING_COST, + STR_SORT_BY_POWER_VS_RUNNING_COST, + STR_SORT_BY_RELIABILITY, + STR_SORT_BY_CARGO_CAPACITY, + INVALID_STRING_ID +}, { + /* Ships */ + STR_SORT_BY_ENGINE_ID, + STR_SORT_BY_COST, + STR_SORT_BY_MAX_SPEED, + STR_SORT_BY_INTRO_DATE, + STR_SORT_BY_NAME, + STR_SORT_BY_RUNNING_COST, + STR_SORT_BY_RELIABILITY, + STR_SORT_BY_CARGO_CAPACITY, + INVALID_STRING_ID +}, { + /* Aircraft */ + STR_SORT_BY_ENGINE_ID, + STR_SORT_BY_COST, + STR_SORT_BY_MAX_SPEED, + STR_SORT_BY_INTRO_DATE, + STR_SORT_BY_NAME, + STR_SORT_BY_RUNNING_COST, + STR_SORT_BY_RELIABILITY, + STR_SORT_BY_CARGO_CAPACITY, + STR_SORT_BY_RANGE, + INVALID_STRING_ID +}}; + +/** Cargo filter functions */ +static bool CDECL CargoFilter(const EngineID *eid, const CargoID cid) +{ + if (cid == CF_ANY) return true; + uint32 refit_mask = GetUnionOfArticulatedRefitMasks(*eid, true) & _standard_cargo_mask; + return (cid == CF_NONE ? refit_mask == 0 : HasBit(refit_mask, cid)); +} + +static GUIEngineList::FilterFunction * const _filter_funcs[] = { + &CargoFilter, +}; + +static int DrawCargoCapacityInfo(int left, int right, int y, EngineID engine) +{ + CargoArray cap; + uint32 refits; + GetArticulatedVehicleCargoesAndRefits(engine, &cap, &refits); + + for (CargoID c = 0; c < NUM_CARGO; c++) { + if (cap[c] == 0) continue; + + SetDParam(0, c); + SetDParam(1, cap[c]); + SetDParam(2, HasBit(refits, c) ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY); + DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY); + y += FONT_HEIGHT_NORMAL; + } + + return y; +} + +/* Draw rail wagon specific details */ +static int DrawRailWagonPurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi) +{ + const Engine *e = Engine::Get(engine_number); + + /* Purchase cost */ + SetDParam(0, e->GetCost()); + DrawString(left, right, y, STR_PURCHASE_INFO_COST); + y += FONT_HEIGHT_NORMAL; + + /* Wagon weight - (including cargo) */ + uint weight = e->GetDisplayWeight(); + SetDParam(0, weight); + uint cargo_weight = (e->CanCarryCargo() ? CargoSpec::Get(e->GetDefaultCargoType())->weight * GetTotalCapacityOfArticulatedParts(engine_number) / 16 : 0); + SetDParam(1, cargo_weight + weight); + DrawString(left, right, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT); + y += FONT_HEIGHT_NORMAL; + + /* Wagon speed limit, displayed if above zero */ + if (_settings_game.vehicle.wagon_speed_limits) { + uint max_speed = e->GetDisplayMaxSpeed(); + if (max_speed > 0) { + SetDParam(0, max_speed); + DrawString(left, right, y, STR_PURCHASE_INFO_SPEED); + y += FONT_HEIGHT_NORMAL; + } + } + + /* Running cost */ + if (rvi->running_cost_class != INVALID_PRICE) { + SetDParam(0, e->GetRunningCost()); + DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST); + y += FONT_HEIGHT_NORMAL; + } + + return y; +} + +/* Draw locomotive specific details */ +static int DrawRailEnginePurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi) +{ + const Engine *e = Engine::Get(engine_number); + + /* Purchase Cost - Engine weight */ + SetDParam(0, e->GetCost()); + SetDParam(1, e->GetDisplayWeight()); + DrawString(left, right, y, STR_PURCHASE_INFO_COST_WEIGHT); + y += FONT_HEIGHT_NORMAL; + + /* Max speed - Engine power */ + SetDParam(0, e->GetDisplayMaxSpeed()); + SetDParam(1, e->GetPower()); + DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_POWER); + y += FONT_HEIGHT_NORMAL; + + /* Max tractive effort - not applicable if old acceleration or maglev */ + if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL && GetRailTypeInfo(rvi->railtype)->acceleration_type != 2) { + SetDParam(0, e->GetDisplayMaxTractiveEffort()); + DrawString(left, right, y, STR_PURCHASE_INFO_MAX_TE); + y += FONT_HEIGHT_NORMAL; + } + + /* Running cost */ + if (rvi->running_cost_class != INVALID_PRICE) { + SetDParam(0, e->GetRunningCost()); + DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST); + y += FONT_HEIGHT_NORMAL; + } + + /* Powered wagons power - Powered wagons extra weight */ + if (rvi->pow_wag_power != 0) { + SetDParam(0, rvi->pow_wag_power); + SetDParam(1, rvi->pow_wag_weight); + DrawString(left, right, y, STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT); + y += FONT_HEIGHT_NORMAL; + } + + return y; +} + +/* Draw road vehicle specific details */ +static int DrawRoadVehPurchaseInfo(int left, int right, int y, EngineID engine_number) +{ + const Engine *e = Engine::Get(engine_number); + + if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) { + /* Purchase Cost */ + SetDParam(0, e->GetCost()); + DrawString(left, right, y, STR_PURCHASE_INFO_COST); + y += FONT_HEIGHT_NORMAL; + + /* Road vehicle weight - (including cargo) */ + int16 weight = e->GetDisplayWeight(); + SetDParam(0, weight); + uint cargo_weight = (e->CanCarryCargo() ? CargoSpec::Get(e->GetDefaultCargoType())->weight * GetTotalCapacityOfArticulatedParts(engine_number) / 16 : 0); + SetDParam(1, cargo_weight + weight); + DrawString(left, right, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT); + y += FONT_HEIGHT_NORMAL; + + /* Max speed - Engine power */ + SetDParam(0, e->GetDisplayMaxSpeed()); + SetDParam(1, e->GetPower()); + DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_POWER); + y += FONT_HEIGHT_NORMAL; + + /* Max tractive effort */ + SetDParam(0, e->GetDisplayMaxTractiveEffort()); + DrawString(left, right, y, STR_PURCHASE_INFO_MAX_TE); + y += FONT_HEIGHT_NORMAL; + } else { + /* Purchase cost - Max speed */ + SetDParam(0, e->GetCost()); + SetDParam(1, e->GetDisplayMaxSpeed()); + DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED); + y += FONT_HEIGHT_NORMAL; + } + + /* Running cost */ + SetDParam(0, e->GetRunningCost()); + DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST); + y += FONT_HEIGHT_NORMAL; + + return y; +} + +/* Draw ship specific details */ +static int DrawShipPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable) +{ + const Engine *e = Engine::Get(engine_number); + + /* Purchase cost - Max speed */ + uint raw_speed = e->GetDisplayMaxSpeed(); + uint ocean_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, true); + uint canal_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, false); + + SetDParam(0, e->GetCost()); + if (ocean_speed == canal_speed) { + SetDParam(1, ocean_speed); + DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED); + y += FONT_HEIGHT_NORMAL; + } else { + DrawString(left, right, y, STR_PURCHASE_INFO_COST); + y += FONT_HEIGHT_NORMAL; + + SetDParam(0, ocean_speed); + DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_OCEAN); + y += FONT_HEIGHT_NORMAL; + + SetDParam(0, canal_speed); + DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_CANAL); + y += FONT_HEIGHT_NORMAL; + } + + /* Cargo type + capacity */ + SetDParam(0, e->GetDefaultCargoType()); + SetDParam(1, e->GetDisplayDefaultCapacity()); + SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY); + DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY); + y += FONT_HEIGHT_NORMAL; + + /* Running cost */ + SetDParam(0, e->GetRunningCost()); + DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST); + y += FONT_HEIGHT_NORMAL; + + return y; +} + +/* Draw aircraft specific details */ +static int DrawAircraftPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable) +{ + const Engine *e = Engine::Get(engine_number); + CargoID cargo = e->GetDefaultCargoType(); + + /* Purchase cost - Max speed */ + SetDParam(0, e->GetCost()); + SetDParam(1, e->GetDisplayMaxSpeed()); + DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED); + y += FONT_HEIGHT_NORMAL; + + /* Cargo capacity */ + uint16 mail_capacity; + uint capacity = e->GetDisplayDefaultCapacity(&mail_capacity); + if (mail_capacity > 0) { + SetDParam(0, cargo); + SetDParam(1, capacity); + SetDParam(2, CT_MAIL); + SetDParam(3, mail_capacity); + DrawString(left, right, y, STR_PURCHASE_INFO_AIRCRAFT_CAPACITY); + } else { + /* Note, if the default capacity is selected by the refit capacity + * callback, then the capacity shown is likely to be incorrect. */ + SetDParam(0, cargo); + SetDParam(1, capacity); + SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY); + DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY); + } + y += FONT_HEIGHT_NORMAL; + + /* Running cost */ + SetDParam(0, e->GetRunningCost()); + DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST); + y += FONT_HEIGHT_NORMAL; + + uint16 range = e->GetRange(); + if (range != 0) { + SetDParam(0, range); + DrawString(left, right, y, STR_PURCHASE_INFO_AIRCRAFT_RANGE); + y += FONT_HEIGHT_NORMAL; + } + + return y; +} + +/** + * Display additional text from NewGRF in the purchase information window + * @param left Left border of text bounding box + * @param right Right border of text bounding box + * @param y Top border of text bounding box + * @param engine Engine to query the additional purchase information for + * @return Bottom border of text bounding box + */ +static uint ShowAdditionalText(int left, int right, int y, EngineID engine) +{ + uint16 callback = GetVehicleCallback(CBID_VEHICLE_ADDITIONAL_TEXT, 0, 0, engine, NULL); + if (callback == CALLBACK_FAILED || callback == 0x400) return y; + const GRFFile *grffile = Engine::Get(engine)->GetGRF(); + if (callback > 0x400) { + ErrorUnknownCallbackResult(grffile->grfid, CBID_VEHICLE_ADDITIONAL_TEXT, callback); + return y; + } + + StartTextRefStackUsage(grffile, 6); + uint result = DrawStringMultiLine(left, right, y, INT32_MAX, GetGRFStringID(grffile->grfid, 0xD000 + callback), TC_BLACK); + StopTextRefStackUsage(); + return result; +} + +/** + * Draw the purchase info details of a vehicle at a given location. + * @param left,right,y location where to draw the info + * @param engine_number the engine of which to draw the info of + * @return y after drawing all the text + */ +int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number) +{ + const Engine *e = Engine::Get(engine_number); + YearMonthDay ymd; + ConvertDateToYMD(e->intro_date, &ymd); + bool refittable = IsArticulatedVehicleRefittable(engine_number); + bool articulated_cargo = false; + + switch (e->type) { + default: NOT_REACHED(); + case VEH_TRAIN: + if (e->u.rail.railveh_type == RAILVEH_WAGON) { + y = DrawRailWagonPurchaseInfo(left, right, y, engine_number, &e->u.rail); + } else { + y = DrawRailEnginePurchaseInfo(left, right, y, engine_number, &e->u.rail); + } + articulated_cargo = true; + break; + + case VEH_ROAD: + y = DrawRoadVehPurchaseInfo(left, right, y, engine_number); + articulated_cargo = true; + break; + + case VEH_SHIP: + y = DrawShipPurchaseInfo(left, right, y, engine_number, refittable); + break; + + case VEH_AIRCRAFT: + y = DrawAircraftPurchaseInfo(left, right, y, engine_number, refittable); + break; + } + + if (articulated_cargo) { + /* Cargo type + capacity, or N/A */ + int new_y = DrawCargoCapacityInfo(left, right, y, engine_number); + + if (new_y == y) { + SetDParam(0, CT_INVALID); + SetDParam(2, STR_EMPTY); + DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY); + y += FONT_HEIGHT_NORMAL; + } else { + y = new_y; + } + } + + /* Draw details that apply to all types except rail wagons. */ + if (e->type != VEH_TRAIN || e->u.rail.railveh_type != RAILVEH_WAGON) { + /* Design date - Life length */ + SetDParam(0, ymd.year); + SetDParam(1, e->GetLifeLengthInDays() / DAYS_IN_LEAP_YEAR); + DrawString(left, right, y, STR_PURCHASE_INFO_DESIGNED_LIFE); + y += FONT_HEIGHT_NORMAL; + + /* Reliability */ + SetDParam(0, ToPercent16(e->reliability)); + DrawString(left, right, y, STR_PURCHASE_INFO_RELIABILITY); + y += FONT_HEIGHT_NORMAL; + } + + if (refittable) y = ShowRefitOptionsList(left, right, y, engine_number); + + /* Additional text from NewGRF */ + y = ShowAdditionalText(left, right, y, engine_number); + + return y; +} + +/** + * Engine drawing loop + * @param type Type of vehicle (VEH_*) + * @param l The left most location of the list + * @param r The right most location of the list + * @param y The top most location of the list + * @param eng_list What engines to draw + * @param min where to start in the list + * @param max where in the list to end + * @param selected_id what engine to highlight as selected, if any + * @param show_count Whether to show the amount of engines or not + * @param selected_group the group to list the engines of + */ +void DrawEngineList(VehicleType type, int l, int r, int y, const GUIEngineList *eng_list, uint16 min, uint16 max, EngineID selected_id, bool show_count, GroupID selected_group) +{ + static const int sprite_y_offsets[] = { -1, -1, -2, -2 }; + + /* Obligatory sanity checks! */ + assert(max <= eng_list->Length()); + + bool rtl = _current_text_dir == TD_RTL; + int step_size = GetEngineListHeight(type); + int sprite_left = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_left; + int sprite_right = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_right; + int sprite_width = sprite_left + sprite_right; + + int sprite_x = rtl ? r - sprite_right - 1 : l + sprite_left + 1; + int sprite_y_offset = sprite_y_offsets[type] + step_size / 2; + + Dimension replace_icon = {0, 0}; + int count_width = 0; + if (show_count) { + replace_icon = GetSpriteSize(SPR_GROUP_REPLACE_ACTIVE); + SetDParamMaxDigits(0, 3, FS_SMALL); + count_width = GetStringBoundingBox(STR_TINY_BLACK_COMA).width; + } + + int text_left = l + (rtl ? WD_FRAMERECT_LEFT + replace_icon.width + 8 + count_width : sprite_width + WD_FRAMETEXT_LEFT); + int text_right = r - (rtl ? sprite_width + WD_FRAMETEXT_RIGHT : WD_FRAMERECT_RIGHT + replace_icon.width + 8 + count_width); + int replace_icon_left = rtl ? l + WD_FRAMERECT_LEFT : r - WD_FRAMERECT_RIGHT - replace_icon.width; + int count_left = l; + int count_right = rtl ? text_left : r - WD_FRAMERECT_RIGHT - replace_icon.width - 8; + + int normal_text_y_offset = (step_size - FONT_HEIGHT_NORMAL) / 2; + int small_text_y_offset = step_size - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 1; + int replace_icon_y_offset = (step_size - replace_icon.height) / 2 - 1; + + for (; min < max; min++, y += step_size) { + const EngineID engine = (*eng_list)[min]; + /* Note: num_engines is only used in the autoreplace GUI, so it is correct to use _local_company here. */ + const uint num_engines = GetGroupNumEngines(_local_company, selected_group, engine); + + const Engine *e = Engine::Get(engine); + bool hidden = HasBit(e->company_hidden, _local_company); + StringID str = hidden ? STR_HIDDEN_ENGINE_NAME : STR_ENGINE_NAME; + TextColour tc = (engine == selected_id) ? TC_WHITE : (TC_NO_SHADE | (hidden ? TC_GREY : TC_BLACK)); + + SetDParam(0, engine); + DrawString(text_left, text_right, y + normal_text_y_offset, str, tc); + DrawVehicleEngine(l, r, sprite_x, y + sprite_y_offset, engine, (show_count && num_engines == 0) ? PALETTE_CRASH : GetEnginePalette(engine, _local_company), EIT_PURCHASE); + if (show_count) { + SetDParam(0, num_engines); + DrawString(count_left, count_right, y + small_text_y_offset, STR_TINY_BLACK_COMA, TC_FROMSTRING, SA_RIGHT | SA_FORCE); + if (EngineHasReplacementForCompany(Company::Get(_local_company), engine, selected_group)) DrawSprite(SPR_GROUP_REPLACE_ACTIVE, num_engines == 0 ? PALETTE_CRASH : PAL_NONE, replace_icon_left, y + replace_icon_y_offset); + } + } +} + +/** + * Display the dropdown for the vehicle sort criteria. + * @param w Parent window (holds the dropdown button). + * @param vehicle_type %Vehicle type being sorted. + * @param selected Currently selected sort criterium. + * @param button Widget button. + */ +void DisplayVehicleSortDropDown(Window *w, VehicleType vehicle_type, int selected, int button) +{ + uint32 hidden_mask = 0; + /* Disable sorting by power or tractive effort when the original acceleration model for road vehicles is being used. */ + if (vehicle_type == VEH_ROAD && _settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) { + SetBit(hidden_mask, 3); // power + SetBit(hidden_mask, 4); // tractive effort + SetBit(hidden_mask, 8); // power by running costs + } + /* Disable sorting by tractive effort when the original acceleration model for trains is being used. */ + if (vehicle_type == VEH_TRAIN && _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) { + SetBit(hidden_mask, 4); // tractive effort + } + ShowDropDownMenu(w, _engine_sort_listing[vehicle_type], selected, button, 0, hidden_mask); +} + +/** GUI for building vehicles. */ +struct BuildVehicleWindow : Window { + VehicleType vehicle_type; ///< Type of vehicles shown in the window. + union { + RailTypeByte railtype; ///< Rail type to show, or #RAILTYPE_END. + RoadTypes roadtypes; ///< Road type to show, or #ROADTYPES_ALL. + } filter; ///< Filter to apply. + bool descending_sort_order; ///< Sort direction, @see _engine_sort_direction + byte sort_criteria; ///< Current sort criterium. + bool show_hidden_engines; ///< State of the 'show hidden engines' button. + bool listview_mode; ///< If set, only display the available vehicles and do not show a 'build' button. + EngineID sel_engine; ///< Currently selected engine, or #INVALID_ENGINE + EngineID rename_engine; ///< Engine being renamed. + GUIEngineList eng_list; + CargoID cargo_filter[NUM_CARGO + 2]; ///< Available cargo filters; CargoID or CF_ANY or CF_NONE + StringID cargo_filter_texts[NUM_CARGO + 3]; ///< Texts for filter_cargo, terminated by INVALID_STRING_ID + byte cargo_filter_criteria; ///< Selected cargo filter + int details_height; ///< Minimal needed height of the details panels (found so far). + Scrollbar *vscroll; + + BuildVehicleWindow(WindowDesc *desc, TileIndex tile, VehicleType type) : Window(desc) + { + this->vehicle_type = type; + this->window_number = tile == INVALID_TILE ? (int)type : tile; + + this->sel_engine = INVALID_ENGINE; + + this->sort_criteria = _engine_sort_last_criteria[type]; + this->descending_sort_order = _engine_sort_last_order[type]; + this->show_hidden_engines = _engine_sort_show_hidden_engines[type]; + + switch (type) { + default: NOT_REACHED(); + case VEH_TRAIN: + this->filter.railtype = (tile == INVALID_TILE) ? RAILTYPE_END : GetRailType(tile); + break; + case VEH_ROAD: + this->filter.roadtypes = (tile == INVALID_TILE) ? ROADTYPES_ALL : GetRoadTypes(tile); + case VEH_SHIP: + case VEH_AIRCRAFT: + break; + } + + this->listview_mode = (this->window_number <= VEH_END); + + this->CreateNestedTree(); + + this->vscroll = this->GetScrollbar(WID_BV_SCROLLBAR); + + /* If we are just viewing the list of vehicles, we do not need the Build button. + * So we just hide it, and enlarge the Rename button by the now vacant place. */ + if (this->listview_mode) this->GetWidget(WID_BV_BUILD_SEL)->SetDisplayedPlane(SZSP_NONE); + + /* disable renaming engines in network games if you are not the server */ + this->SetWidgetDisabledState(WID_BV_RENAME, _networking && !_network_server); + + NWidgetCore *widget = this->GetWidget(WID_BV_LIST); + widget->tool_tip = STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP + type; + + widget = this->GetWidget(WID_BV_SHOW_HIDE); + widget->tool_tip = STR_BUY_VEHICLE_TRAIN_HIDE_SHOW_TOGGLE_TOOLTIP + type; + + widget = this->GetWidget(WID_BV_BUILD); + widget->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + type; + widget->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP + type; + + widget = this->GetWidget(WID_BV_RENAME); + widget->widget_data = STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON + type; + widget->tool_tip = STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP + type; + + widget = this->GetWidget(WID_BV_SHOW_HIDDEN_ENGINES); + widget->widget_data = STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN + type; + widget->tool_tip = STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN_TOOLTIP + type; + widget->SetLowered(this->show_hidden_engines); + + this->details_height = ((this->vehicle_type == VEH_TRAIN) ? 10 : 9) * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + + this->FinishInitNested(tile == INVALID_TILE ? (int)type : tile); + + this->owner = (tile != INVALID_TILE) ? GetTileOwner(tile) : _local_company; + + this->eng_list.ForceRebuild(); + this->GenerateBuildList(); // generate the list, since we need it in the next line + /* Select the first engine in the list as default when opening the window */ + if (this->eng_list.Length() > 0) this->sel_engine = this->eng_list[0]; + } + + /** Populate the filter list and set the cargo filter criteria. */ + void SetCargoFilterArray() + { + uint filter_items = 0; + + /* Add item for disabling filtering. */ + this->cargo_filter[filter_items] = CF_ANY; + this->cargo_filter_texts[filter_items] = STR_PURCHASE_INFO_ALL_TYPES; + filter_items++; + + /* Add item for vehicles not carrying anything, e.g. train engines. + * This could also be useful for eyecandy vehicles of other types, but is likely too confusing for joe, */ + if (this->vehicle_type == VEH_TRAIN) { + this->cargo_filter[filter_items] = CF_NONE; + this->cargo_filter_texts[filter_items] = STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE; + filter_items++; + } + + /* Collect available cargo types for filtering. */ + const CargoSpec *cs; + FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { + this->cargo_filter[filter_items] = cs->Index(); + this->cargo_filter_texts[filter_items] = cs->name; + filter_items++; + } + + /* Terminate the filter list. */ + this->cargo_filter_texts[filter_items] = INVALID_STRING_ID; + + /* If not found, the cargo criteria will be set to all cargoes. */ + this->cargo_filter_criteria = 0; + + /* Find the last cargo filter criteria. */ + for (uint i = 0; i < filter_items; i++) { + if (this->cargo_filter[i] == _engine_sort_last_cargo_criteria[this->vehicle_type]) { + this->cargo_filter_criteria = i; + break; + } + } + + this->eng_list.SetFilterFuncs(_filter_funcs); + this->eng_list.SetFilterState(this->cargo_filter[this->cargo_filter_criteria] != CF_ANY); + } + + void OnInit() + { + this->SetCargoFilterArray(); + } + + /** Filter the engine list against the currently selected cargo filter */ + void FilterEngineList() + { + this->eng_list.Filter(this->cargo_filter[this->cargo_filter_criteria]); + if (0 == this->eng_list.Length()) { // no engine passed through the filter, invalidate the previously selected engine + this->sel_engine = INVALID_ENGINE; + } else if (!this->eng_list.Contains(this->sel_engine)) { // previously selected engine didn't pass the filter, select the first engine of the list + this->sel_engine = this->eng_list[0]; + } + } + + /** Filter a single engine */ + bool FilterSingleEngine(EngineID eid) + { + CargoID filter_type = this->cargo_filter[this->cargo_filter_criteria]; + return (filter_type == CF_ANY || CargoFilter(&eid, filter_type)); + } + + /* Figure out what train EngineIDs to put in the list */ + void GenerateBuildTrainList() + { + EngineID sel_id = INVALID_ENGINE; + int num_engines = 0; + int num_wagons = 0; + + this->filter.railtype = (this->listview_mode) ? RAILTYPE_END : GetRailType(this->window_number); + + this->eng_list.Clear(); + + /* Make list of all available train engines and wagons. + * Also check to see if the previously selected engine is still available, + * and if not, reset selection to INVALID_ENGINE. This could be the case + * when engines become obsolete and are removed */ + const Engine *e; + FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) { + if (!this->show_hidden_engines && e->IsHidden(_local_company)) continue; + EngineID eid = e->index; + const RailVehicleInfo *rvi = &e->u.rail; + + if (this->filter.railtype != RAILTYPE_END && !HasPowerOnRail(rvi->railtype, this->filter.railtype)) continue; + if (!IsEngineBuildable(eid, VEH_TRAIN, _local_company)) continue; + + /* Filter now! So num_engines and num_wagons is valid */ + if (!FilterSingleEngine(eid)) continue; + + *this->eng_list.Append() = eid; + + if (rvi->railveh_type != RAILVEH_WAGON) { + num_engines++; + } else { + num_wagons++; + } + + if (eid == this->sel_engine) sel_id = eid; + } + + this->sel_engine = sel_id; + + /* make engines first, and then wagons, sorted by selected sort_criteria */ + _engine_sort_direction = false; + EngList_Sort(&this->eng_list, TrainEnginesThenWagonsSorter); + + /* and then sort engines */ + _engine_sort_direction = this->descending_sort_order; + EngList_SortPartial(&this->eng_list, _engine_sort_functions[0][this->sort_criteria], 0, num_engines); + + /* and finally sort wagons */ + EngList_SortPartial(&this->eng_list, _engine_sort_functions[0][this->sort_criteria], num_engines, num_wagons); + } + + /* Figure out what road vehicle EngineIDs to put in the list */ + void GenerateBuildRoadVehList() + { + EngineID sel_id = INVALID_ENGINE; + + this->eng_list.Clear(); + + const Engine *e; + FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) { + if (!this->show_hidden_engines && e->IsHidden(_local_company)) continue; + EngineID eid = e->index; + if (!IsEngineBuildable(eid, VEH_ROAD, _local_company)) continue; + if (!HasBit(this->filter.roadtypes, HasBit(EngInfo(eid)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD)) continue; + *this->eng_list.Append() = eid; + + if (eid == this->sel_engine) sel_id = eid; + } + this->sel_engine = sel_id; + } + + /* Figure out what ship EngineIDs to put in the list */ + void GenerateBuildShipList() + { + EngineID sel_id = INVALID_ENGINE; + this->eng_list.Clear(); + + const Engine *e; + FOR_ALL_ENGINES_OF_TYPE(e, VEH_SHIP) { + if (!this->show_hidden_engines && e->IsHidden(_local_company)) continue; + EngineID eid = e->index; + if (!IsEngineBuildable(eid, VEH_SHIP, _local_company)) continue; + *this->eng_list.Append() = eid; + + if (eid == this->sel_engine) sel_id = eid; + } + this->sel_engine = sel_id; + } + + /* Figure out what aircraft EngineIDs to put in the list */ + void GenerateBuildAircraftList() + { + EngineID sel_id = INVALID_ENGINE; + + this->eng_list.Clear(); + + const Station *st = this->listview_mode ? NULL : Station::GetByTile(this->window_number); + + /* Make list of all available planes. + * Also check to see if the previously selected plane is still available, + * and if not, reset selection to INVALID_ENGINE. This could be the case + * when planes become obsolete and are removed */ + const Engine *e; + FOR_ALL_ENGINES_OF_TYPE(e, VEH_AIRCRAFT) { + if (!this->show_hidden_engines && e->IsHidden(_local_company)) continue; + EngineID eid = e->index; + if (!IsEngineBuildable(eid, VEH_AIRCRAFT, _local_company)) continue; + /* First VEH_END window_numbers are fake to allow a window open for all different types at once */ + if (!this->listview_mode && !CanVehicleUseStation(eid, st)) continue; + + *this->eng_list.Append() = eid; + if (eid == this->sel_engine) sel_id = eid; + } + + this->sel_engine = sel_id; + } + + /* Generate the list of vehicles */ + void GenerateBuildList() + { + if (!this->eng_list.NeedRebuild()) return; + switch (this->vehicle_type) { + default: NOT_REACHED(); + case VEH_TRAIN: + this->GenerateBuildTrainList(); + this->eng_list.Compact(); + this->eng_list.RebuildDone(); + return; // trains should not reach the last sorting + case VEH_ROAD: + this->GenerateBuildRoadVehList(); + break; + case VEH_SHIP: + this->GenerateBuildShipList(); + break; + case VEH_AIRCRAFT: + this->GenerateBuildAircraftList(); + break; + } + + this->FilterEngineList(); + + _engine_sort_direction = this->descending_sort_order; + EngList_Sort(&this->eng_list, _engine_sort_functions[this->vehicle_type][this->sort_criteria]); + + this->eng_list.Compact(); + this->eng_list.RebuildDone(); + } + + void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_BV_SORT_ASCENDING_DESCENDING: + this->descending_sort_order ^= true; + _engine_sort_last_order[this->vehicle_type] = this->descending_sort_order; + this->eng_list.ForceRebuild(); + this->SetDirty(); + break; + + case WID_BV_SHOW_HIDDEN_ENGINES: + this->show_hidden_engines ^= true; + _engine_sort_show_hidden_engines[this->vehicle_type] = this->show_hidden_engines; + this->eng_list.ForceRebuild(); + this->SetWidgetLoweredState(widget, this->show_hidden_engines); + this->SetDirty(); + break; + + case WID_BV_LIST: { + uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BV_LIST); + size_t num_items = this->eng_list.Length(); + this->sel_engine = (i < num_items) ? this->eng_list[i] : INVALID_ENGINE; + this->SetDirty(); + if (_ctrl_pressed) { + this->OnClick(pt, WID_BV_SHOW_HIDE, 1); + } else if (click_count > 1 && !this->listview_mode) { + this->OnClick(pt, WID_BV_BUILD, 1); + } + break; + } + + case WID_BV_SORT_DROPDOWN: // Select sorting criteria dropdown menu + DisplayVehicleSortDropDown(this, this->vehicle_type, this->sort_criteria, WID_BV_SORT_DROPDOWN); + break; + + case WID_BV_CARGO_FILTER_DROPDOWN: // Select cargo filtering criteria dropdown menu + ShowDropDownMenu(this, this->cargo_filter_texts, this->cargo_filter_criteria, WID_BV_CARGO_FILTER_DROPDOWN, 0, 0); + break; + + case WID_BV_SHOW_HIDE: { + const Engine *e = (this->sel_engine == INVALID_ENGINE) ? NULL : Engine::Get(this->sel_engine); + if (e != NULL) { + DoCommandP(0, 0, this->sel_engine | (e->IsHidden(_current_company) ? 0 : (1u << 31)), CMD_SET_VEHICLE_VISIBILITY); + } + break; + } + + case WID_BV_BUILD: { + EngineID sel_eng = this->sel_engine; + if (sel_eng != INVALID_ENGINE) { + CommandCallback *callback = (this->vehicle_type == VEH_TRAIN && RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) ? CcBuildWagon : CcBuildPrimaryVehicle; + DoCommandP(this->window_number, sel_eng, 0, GetCmdBuildVeh(this->vehicle_type), callback); + } + break; + } + + case WID_BV_RENAME: { + EngineID sel_eng = this->sel_engine; + if (sel_eng != INVALID_ENGINE) { + this->rename_engine = sel_eng; + SetDParam(0, sel_eng); + ShowQueryString(STR_ENGINE_NAME, STR_QUERY_RENAME_TRAIN_TYPE_CAPTION + this->vehicle_type, MAX_LENGTH_ENGINE_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); + } + break; + } + } + } + + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (!gui_scope) return; + /* When switching to original acceleration model for road vehicles, clear the selected sort criteria if it is not available now. */ + if (this->vehicle_type == VEH_ROAD && + _settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL && + this->sort_criteria > 7) { + this->sort_criteria = 0; + _engine_sort_last_criteria[VEH_ROAD] = 0; + } + this->eng_list.ForceRebuild(); + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_BV_CAPTION: + if (this->vehicle_type == VEH_TRAIN && !this->listview_mode) { + const RailtypeInfo *rti = GetRailTypeInfo(this->filter.railtype); + SetDParam(0, rti->strings.build_caption); + } else { + SetDParam(0, (this->listview_mode ? STR_VEHICLE_LIST_AVAILABLE_TRAINS : STR_BUY_VEHICLE_TRAIN_ALL_CAPTION) + this->vehicle_type); + } + break; + + case WID_BV_SORT_DROPDOWN: + SetDParam(0, _engine_sort_listing[this->vehicle_type][this->sort_criteria]); + break; + + case WID_BV_CARGO_FILTER_DROPDOWN: + SetDParam(0, this->cargo_filter_texts[this->cargo_filter_criteria]); + break; + + case WID_BV_SHOW_HIDE: { + const Engine *e = (this->sel_engine == INVALID_ENGINE) ? NULL : Engine::Get(this->sel_engine); + if (e != NULL && e->IsHidden(_local_company)) { + SetDParam(0, STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type); + } else { + SetDParam(0, STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type); + } + break; + } + } + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_BV_LIST: + resize->height = GetEngineListHeight(this->vehicle_type); + size->height = 3 * resize->height; + size->width = max(size->width, GetVehicleImageCellSize(this->vehicle_type, EIT_PURCHASE).extend_left + GetVehicleImageCellSize(this->vehicle_type, EIT_PURCHASE).extend_right + 165); + break; + + case WID_BV_PANEL: + size->height = this->details_height; + break; + + case WID_BV_SORT_ASCENDING_DESCENDING: { + Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); + d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better. + d.height += padding.height; + *size = maxdim(*size, d); + break; + } + + case WID_BV_SHOW_HIDE: + *size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type); + *size = maxdim(*size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type)); + size->width += padding.width; + size->height += padding.height; + break; + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_BV_LIST: + DrawEngineList(this->vehicle_type, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, &this->eng_list, this->vscroll->GetPosition(), min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->eng_list.Length()), this->sel_engine, false, DEFAULT_GROUP); + break; + + case WID_BV_SORT_ASCENDING_DESCENDING: + this->DrawSortButtonState(WID_BV_SORT_ASCENDING_DESCENDING, this->descending_sort_order ? SBS_DOWN : SBS_UP); + break; + } + } + + virtual void OnPaint() + { + this->GenerateBuildList(); + this->vscroll->SetCount(this->eng_list.Length()); + + this->SetWidgetDisabledState(WID_BV_SHOW_HIDE, this->sel_engine == INVALID_ENGINE); + + this->DrawWidgets(); + + if (!this->IsShaded()) { + int needed_height = this->details_height; + /* Draw details panels. */ + if (this->sel_engine != INVALID_ENGINE) { + NWidgetBase *nwi = this->GetWidget(WID_BV_PANEL); + int text_end = DrawVehiclePurchaseInfo(nwi->pos_x + WD_FRAMETEXT_LEFT, nwi->pos_x + nwi->current_x - WD_FRAMETEXT_RIGHT, + nwi->pos_y + WD_FRAMERECT_TOP, this->sel_engine); + needed_height = max(needed_height, text_end - (int)nwi->pos_y + WD_FRAMERECT_BOTTOM); + } + if (needed_height != this->details_height) { // Details window are not high enough, enlarge them. + int resize = needed_height - this->details_height; + this->details_height = needed_height; + this->ReInit(0, resize); + return; + } + } + } + + virtual void OnQueryTextFinished(char *str) + { + if (str == NULL) return; + + DoCommandP(0, this->rename_engine, 0, CMD_RENAME_ENGINE | CMD_MSG(STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this->vehicle_type), NULL, str); + } + + virtual void OnDropdownSelect(int widget, int index) + { + switch (widget) { + case WID_BV_SORT_DROPDOWN: + if (this->sort_criteria != index) { + this->sort_criteria = index; + _engine_sort_last_criteria[this->vehicle_type] = this->sort_criteria; + this->eng_list.ForceRebuild(); + } + break; + + case WID_BV_CARGO_FILTER_DROPDOWN: // Select a cargo filter criteria + if (this->cargo_filter_criteria != index) { + this->cargo_filter_criteria = index; + _engine_sort_last_cargo_criteria[this->vehicle_type] = this->cargo_filter[this->cargo_filter_criteria]; + /* deactivate filter if criteria is 'Show All', activate it otherwise */ + this->eng_list.SetFilterState(this->cargo_filter[this->cargo_filter_criteria] != CF_ANY); + this->eng_list.ForceRebuild(); + } + break; + } + this->SetDirty(); + } + + virtual void OnResize() + { + this->vscroll->SetCapacityFromWidget(this, WID_BV_LIST); + } +}; + +static WindowDesc _build_vehicle_desc( + WDP_AUTO, "build_vehicle", 240, 268, + WC_BUILD_VEHICLE, WC_NONE, + WDF_CONSTRUCTION, + _nested_build_vehicle_widgets, lengthof(_nested_build_vehicle_widgets) +); + +void ShowBuildVehicleWindow(TileIndex tile, VehicleType type) +{ + /* We want to be able to open both Available Train as Available Ships, + * so if tile == INVALID_TILE (Available XXX Window), use 'type' as unique number. + * As it always is a low value, it won't collide with any real tile + * number. */ + uint num = (tile == INVALID_TILE) ? (int)type : tile; + + assert(IsCompanyBuildableVehicleType(type)); + + DeleteWindowById(WC_BUILD_VEHICLE, num); + + new BuildVehicleWindow(&_build_vehicle_desc, tile, type); +} diff --git a/src/cargo_type.h b/src/cargo_type.h new file mode 100644 index 0000000..7b7168a --- /dev/null +++ b/src/cargo_type.h @@ -0,0 +1,149 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file cargo_type.h Types related to cargoes... */ + +#ifndef CARGO_TYPE_H +#define CARGO_TYPE_H + +#include "core/enum_type.hpp" + +/** + * Cargo slots to indicate a cargo type within a game. + * Numbers are re-used between different climates. + * @see CargoTypes + */ +typedef byte CargoID; + +/** Available types of cargo */ +enum CargoTypes { + /* Temperate */ + CT_PASSENGERS = 0, + CT_COAL = 1, + CT_MAIL = 2, + CT_OIL = 3, + CT_LIVESTOCK = 4, + CT_GOODS = 5, + CT_GRAIN = 6, + CT_WOOD = 7, + CT_IRON_ORE = 8, + CT_STEEL = 9, + CT_VALUABLES = 10, + + /* Arctic */ + CT_WHEAT = 6, + CT_HILLY_UNUSED = 8, + CT_PAPER = 9, + CT_GOLD = 10, + CT_FOOD = 11, + + /* Tropic */ + CT_RUBBER = 1, + CT_FRUIT = 4, + CT_MAIZE = 6, + CT_COPPER_ORE = 8, + CT_WATER = 9, + CT_DIAMONDS = 10, + + /* Toyland */ + CT_SUGAR = 1, + CT_TOYS = 3, + CT_BATTERIES = 4, + CT_CANDY = 5, + CT_TOFFEE = 6, + CT_COLA = 7, + CT_COTTON_CANDY = 8, + CT_BUBBLES = 9, + CT_PLASTIC = 10, + CT_FIZZY_DRINKS = 11, + + NUM_CARGO = 32, ///< Maximal number of cargo types in a game. + + CT_AUTO_REFIT = 0xFD, ///< Automatically choose cargo type when doing auto refitting. + CT_NO_REFIT = 0xFE, ///< Do not refit cargo of a vehicle (used in vehicle orders and auto-replace/auto-new). + CT_INVALID = 0xFF, ///< Invalid cargo type. +}; + +/** Class for storing amounts of cargo */ +struct CargoArray { +private: + uint amount[NUM_CARGO]; ///< Amount of each type of cargo. + +public: + /** Default constructor. */ + inline CargoArray() + { + this->Clear(); + } + + /** Reset all entries. */ + inline void Clear() + { + memset(this->amount, 0, sizeof(this->amount)); + } + + /** + * Read/write access to an amount of a specific cargo type. + * @param cargo Cargo type to access. + */ + inline uint &operator[](CargoID cargo) + { + return this->amount[cargo]; + } + + /** + * Read-only access to an amount of a specific cargo type. + * @param cargo Cargo type to access. + */ + inline const uint &operator[](CargoID cargo) const + { + return this->amount[cargo]; + } + + /** + * Get the sum of all cargo amounts. + * @return The sum. + */ + template + inline const T GetSum() const + { + T ret = 0; + for (size_t i = 0; i < lengthof(this->amount); i++) { + ret += this->amount[i]; + } + return ret; + } + + /** + * Get the amount of cargos that have an amount. + * @return The amount. + */ + inline byte GetCount() const + { + byte count = 0; + for (size_t i = 0; i < lengthof(this->amount); i++) { + if (this->amount[i] != 0) count++; + } + return count; + } +}; + + +/** Types of cargo source and destination */ +enum SourceType { + ST_INDUSTRY, ///< Source/destination is an industry + ST_TOWN, ///< Source/destination is a town + ST_HEADQUARTERS, ///< Source/destination are company headquarters +}; +typedef SimpleTinyEnumT SourceTypeByte; ///< The SourceType packed into a byte for savegame purposes. + +typedef uint16 SourceID; ///< Contains either industry ID, town ID or company ID (or INVALID_SOURCE) +static const SourceID INVALID_SOURCE = 0xFFFF; ///< Invalid/unknown index of source + +#endif /* CARGO_TYPE_H */ diff --git a/src/cargoaction.cpp b/src/cargoaction.cpp new file mode 100644 index 0000000..96ddc37 --- /dev/null +++ b/src/cargoaction.cpp @@ -0,0 +1,240 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file cargoaction.cpp Implementation of cargo actions. */ + +#include "stdafx.h" +#include "economy_base.h" +#include "cargoaction.h" +#include "station_base.h" + +#include "safeguards.h" + +/** + * Decides if a packet needs to be split. + * @param cp Packet to be either split or moved in one piece. + * @return Either new packet if splitting was necessary or the given one + * otherwise. + */ +template +CargoPacket *CargoMovement::Preprocess(CargoPacket *cp) +{ + if (this->max_move < cp->Count()) { + cp = cp->Split(this->max_move); + this->max_move = 0; + } else { + this->max_move -= cp->Count(); + } + return cp; +} + +/** + * Determines the amount of cargo to be removed from a packet and removes that + * from the metadata of the list. + * @param cp Packet to be removed completely or partially. + * @return Amount of cargo to be removed. + */ +template +uint CargoRemoval::Preprocess(CargoPacket *cp) +{ + if (this->max_move >= cp->Count()) { + this->max_move -= cp->Count(); + return cp->Count(); + } else { + uint ret = this->max_move; + this->max_move = 0; + return ret; + } +} + +/** + * Finalize cargo removal. Either delete the packet or reduce it. + * @param cp Packet to be removed or reduced. + * @param remove Amount of cargo to be removed. + * @return True if the packet was deleted, False if it was reduced. + */ +template +bool CargoRemoval::Postprocess(CargoPacket *cp, uint remove) +{ + if (remove == cp->Count()) { + delete cp; + return true; + } else { + cp->Reduce(remove); + return false; + } +} + +/** + * Removes some cargo from a StationCargoList. + * @param cp Packet to be removed. + * @return True if the packet was completely delivered, false if only part of + * it was. + */ +template<> +bool CargoRemoval::operator()(CargoPacket *cp) +{ + uint remove = this->Preprocess(cp); + this->source->RemoveFromCache(cp, remove); + return this->Postprocess(cp, remove); +} + +/** + * Removes some cargo from a VehicleCargoList. + * @param cp Packet to be removed. + * @return True if the packet was completely delivered, false if only part of + * it was. + */ +template<> +bool CargoRemoval::operator()(CargoPacket *cp) +{ + uint remove = this->Preprocess(cp); + this->source->RemoveFromMeta(cp, VehicleCargoList::MTA_KEEP, remove); + return this->Postprocess(cp, remove); +} + +/** + * Delivers some cargo. + * @param cp Packet to be delivered. + * @return True if the packet was completely delivered, false if only part of + * it was. + */ +bool CargoDelivery::operator()(CargoPacket *cp) +{ + uint remove = this->Preprocess(cp); + this->source->RemoveFromMeta(cp, VehicleCargoList::MTA_DELIVER, remove); + this->payment->PayFinalDelivery(cp, remove); + return this->Postprocess(cp, remove); +} + +/** + * Loads some cargo onto a vehicle. + * @param cp Packet to be loaded. + * @return True if the packet was completely loaded, false if part of it was. + */ +bool CargoLoad::operator()(CargoPacket *cp) +{ + CargoPacket *cp_new = this->Preprocess(cp); + if (cp_new == NULL) return false; + cp_new->SetLoadPlace(this->load_place); + this->source->RemoveFromCache(cp_new, cp_new->Count()); + this->destination->Append(cp_new, VehicleCargoList::MTA_KEEP); + return cp_new == cp; +} + +/** + * Reserves some cargo for loading. + * @param cp Packet to be reserved. + * @return True if the packet was completely reserved, false if part of it was. + */ +bool CargoReservation::operator()(CargoPacket *cp) +{ + CargoPacket *cp_new = this->Preprocess(cp); + if (cp_new == NULL) return false; + cp_new->SetLoadPlace(this->load_place); + this->source->reserved_count += cp_new->Count(); + this->source->RemoveFromCache(cp_new, cp_new->Count()); + this->destination->Append(cp_new, VehicleCargoList::MTA_LOAD); + return cp_new == cp; +} + +/** + * Returns some reserved cargo. + * @param cp Packet to be returned. + * @return True if the packet was completely returned, false if part of it was. + */ +bool CargoReturn::operator()(CargoPacket *cp) +{ + CargoPacket *cp_new = this->Preprocess(cp); + if (cp_new == NULL) cp_new = cp; + assert(cp_new->Count() <= this->destination->reserved_count); + this->source->RemoveFromMeta(cp_new, VehicleCargoList::MTA_LOAD, cp_new->Count()); + this->destination->reserved_count -= cp_new->Count(); + this->destination->Append(cp_new, this->next); + return cp_new == cp; +} + +/** + * Transfers some cargo from a vehicle to a station. + * @param cp Packet to be transfered. + * @return True if the packet was completely reserved, false if part of it was. + */ +bool CargoTransfer::operator()(CargoPacket *cp) +{ + CargoPacket *cp_new = this->Preprocess(cp); + if (cp_new == NULL) return false; + this->source->RemoveFromMeta(cp_new, VehicleCargoList::MTA_TRANSFER, cp_new->Count()); + /* No transfer credits here as they were already granted during Stage(). */ + this->destination->Append(cp_new, cp_new->NextStation()); + return cp_new == cp; +} + +/** + * Shifts some cargo from a vehicle to another one. + * @param cp Packet to be shifted. + * @return True if the packet was completely shifted, false if part of it was. + */ +bool CargoShift::operator()(CargoPacket *cp) +{ + CargoPacket *cp_new = this->Preprocess(cp); + if (cp_new == NULL) cp_new = cp; + this->source->RemoveFromMeta(cp_new, VehicleCargoList::MTA_KEEP, cp_new->Count()); + this->destination->Append(cp_new, VehicleCargoList::MTA_KEEP); + return cp_new == cp; +} + +/** + * Reroutes some cargo from one Station sublist to another. + * @param cp Packet to be rerouted. + * @return True if the packet was completely rerouted, false if part of it was. + */ +bool StationCargoReroute::operator()(CargoPacket *cp) +{ + CargoPacket *cp_new = this->Preprocess(cp); + if (cp_new == NULL) cp_new = cp; + StationID next = this->ge->GetVia(cp_new->SourceStation(), this->avoid, this->avoid2); + assert(next != this->avoid && next != this->avoid2); + if (this->source != this->destination) { + this->source->RemoveFromCache(cp_new, cp_new->Count()); + this->destination->AddToCache(cp_new); + } + + /* Legal, as insert doesn't invalidate iterators in the MultiMap, however + * this might insert the packet between range.first and range.second (which might be end()) + * This is why we check for GetKey above to avoid infinite loops. */ + this->destination->packets.Insert(next, cp_new); + return cp_new == cp; +} + +/** + * Reroutes some cargo in a VehicleCargoList. + * @param cp Packet to be rerouted. + * @return True if the packet was completely rerouted, false if part of it was. + */ +bool VehicleCargoReroute::operator()(CargoPacket *cp) +{ + CargoPacket *cp_new = this->Preprocess(cp); + if (cp_new == NULL) cp_new = cp; + if (cp_new->NextStation() == this->avoid || cp_new->NextStation() == this->avoid2) { + cp->SetNextStation(this->ge->GetVia(cp_new->SourceStation(), this->avoid, this->avoid2)); + } + if (this->source != this->destination) { + this->source->RemoveFromMeta(cp_new, VehicleCargoList::MTA_TRANSFER, cp_new->Count()); + this->destination->AddToMeta(cp_new, VehicleCargoList::MTA_TRANSFER); + } + + /* Legal, as front pushing doesn't invalidate iterators in std::list. */ + this->destination->packets.push_front(cp_new); + return cp_new == cp; +} + +template uint CargoRemoval::Preprocess(CargoPacket *cp); +template uint CargoRemoval::Preprocess(CargoPacket *cp); +template bool CargoRemoval::Postprocess(CargoPacket *cp, uint remove); +template bool CargoRemoval::Postprocess(CargoPacket *cp, uint remove); diff --git a/src/cargoaction.h b/src/cargoaction.h new file mode 100644 index 0000000..0311efc --- /dev/null +++ b/src/cargoaction.h @@ -0,0 +1,146 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file cargoaction.h Actions to be applied to cargo packets. */ + +#ifndef CARGOACTION_H +#define CARGOACTION_H + +#include "cargopacket.h" + +/** + * Abstract action of removing cargo from a vehicle or a station. + * @tparam Tsource CargoList subclass to remove cargo from. + */ +template +class CargoRemoval { +protected: + Tsource *source; ///< Source of the cargo. + uint max_move; ///< Maximum amount of cargo to be removed with this action. + uint Preprocess(CargoPacket *cp); + bool Postprocess(CargoPacket *cp, uint remove); +public: + CargoRemoval(Tsource *source, uint max_move) : source(source), max_move(max_move) {} + + /** + * Returns how much more cargo can be removed with this action. + * @return Amount of cargo this action can still remove. + */ + uint MaxMove() { return this->max_move; } + + bool operator()(CargoPacket *cp); +}; + +/** Action of final delivery of cargo. */ +class CargoDelivery : public CargoRemoval { +protected: + CargoPayment *payment; ///< Payment object where payments will be registered. +public: + CargoDelivery(VehicleCargoList *source, uint max_move, CargoPayment *payment) : + CargoRemoval(source, max_move), payment(payment) {} + bool operator()(CargoPacket *cp); +}; + +/** + * Abstract action for moving cargo from one list to another. + * @tparam Tsource CargoList subclass to remove cargo from. + * @tparam Tdest CargoList subclass to add cargo to. + */ +template +class CargoMovement { +protected: + Tsource *source; ///< Source of the cargo. + Tdest *destination; ///< Destination for the cargo. + uint max_move; ///< Maximum amount of cargo to be moved with this action. + CargoPacket *Preprocess(CargoPacket *cp); +public: + CargoMovement(Tsource *source, Tdest *destination, uint max_move) : source(source), destination(destination), max_move(max_move) {} + + /** + * Returns how much more cargo can be moved with this action. + * @return Amount of cargo this action can still move. + */ + uint MaxMove() { return this->max_move; } +}; + +/** Action of transferring cargo from a vehicle to a station. */ +class CargoTransfer : public CargoMovement { +public: + CargoTransfer(VehicleCargoList *source, StationCargoList *destination, uint max_move) : + CargoMovement(source, destination, max_move) {} + bool operator()(CargoPacket *cp); +}; + +/** Action of loading cargo from a station onto a vehicle. */ +class CargoLoad : public CargoMovement { +protected: + TileIndex load_place; ///< TileIndex to be saved in the packets' loaded_at_xy. +public: + CargoLoad(StationCargoList *source, VehicleCargoList *destination, uint max_move, TileIndex load_place) : + CargoMovement(source, destination, max_move), load_place(load_place) {} + bool operator()(CargoPacket *cp); +}; + +/** Action of reserving cargo from a station to be loaded onto a vehicle. */ +class CargoReservation : public CargoLoad { +public: + CargoReservation(StationCargoList *source, VehicleCargoList *destination, uint max_move, TileIndex load_place) : + CargoLoad(source, destination, max_move, load_place) {} + bool operator()(CargoPacket *cp); +}; + +/** Action of returning previously reserved cargo from the vehicle to the station. */ +class CargoReturn : public CargoMovement { + StationID next; +public: + CargoReturn(VehicleCargoList *source, StationCargoList *destination, uint max_move, StationID next) : + CargoMovement(source, destination, max_move), next(next) {} + bool operator()(CargoPacket *cp); +}; + +/** Action of shifting cargo from one vehicle to another. */ +class CargoShift : public CargoMovement { +public: + CargoShift(VehicleCargoList *source, VehicleCargoList *destination, uint max_move) : + CargoMovement(source, destination, max_move) {} + bool operator()(CargoPacket *cp); +}; + +/** Action of rerouting cargo between different cargo lists and/or next hops. */ +template +class CargoReroute : public CargoMovement { +protected: + StationID avoid; + StationID avoid2; + const GoodsEntry *ge; +public: + CargoReroute(Tlist *source, Tlist *dest, uint max_move, StationID avoid, StationID avoid2, const GoodsEntry *ge) : + CargoMovement(source, dest, max_move), avoid(avoid), avoid2(avoid2), ge(ge) {} +}; + +/** Action of rerouting cargo in a station. */ +class StationCargoReroute : public CargoReroute { +public: + StationCargoReroute(StationCargoList *source, StationCargoList *dest, uint max_move, StationID avoid, StationID avoid2, const GoodsEntry *ge) : + CargoReroute(source, dest, max_move, avoid, avoid2, ge) {} + bool operator()(CargoPacket *cp); +}; + +/** Action of rerouting cargo staged for transfer in a vehicle. */ +class VehicleCargoReroute : public CargoReroute { +public: + VehicleCargoReroute(VehicleCargoList *source, VehicleCargoList *dest, uint max_move, StationID avoid, StationID avoid2, const GoodsEntry *ge) : + CargoReroute(source, dest, max_move, avoid, avoid2, ge) + { + assert(this->max_move <= source->ActionCount(VehicleCargoList::MTA_TRANSFER)); + } + bool operator()(CargoPacket *cp); +}; + +#endif /* CARGOACTION_H */ diff --git a/src/cargomonitor.cpp b/src/cargomonitor.cpp new file mode 100644 index 0000000..b1d52d6 --- /dev/null +++ b/src/cargomonitor.cpp @@ -0,0 +1,159 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file cargomonitor.cpp Implementation of the cargo transport monitoring. */ + +#include "stdafx.h" +#include "cargomonitor.h" +#include "station_base.h" + +#include "safeguards.h" + +CargoMonitorMap _cargo_pickups; ///< Map of monitored pick-ups to the amount since last query/activation. +CargoMonitorMap _cargo_deliveries; ///< Map of monitored deliveries to the amount since last query/activation. + +/** + * Helper method for #ClearCargoPickupMonitoring and #ClearCargoDeliveryMonitoring. + * Clears all monitors that belong to the specified company or all if #INVALID_OWNER + * is specified as company. + * @param cargo_monitor_map reference to the cargo monitor map to operate on. + * @param company company to clear cargo monitors for or #INVALID_OWNER if all cargo monitors should be cleared. + */ +static void ClearCargoMonitoring(CargoMonitorMap &cargo_monitor_map, CompanyID company = INVALID_OWNER) +{ + if (company == INVALID_OWNER) { + cargo_monitor_map.clear(); + return; + } + + CargoMonitorMap::iterator next; + for (CargoMonitorMap::iterator it = cargo_monitor_map.begin(); it != cargo_monitor_map.end(); it = next) { + next = it; + next++; + if (DecodeMonitorCompany(it->first) == company) { + cargo_monitor_map.erase(it); + } + } +} + +/** + * Clear all pick-up cargo monitors. + * @param company clear all pick-up monitors for this company or if #INVALID_OWNER + * is passed, all pick-up monitors are cleared regardless of company. + */ +void ClearCargoPickupMonitoring(CompanyID company) +{ + ClearCargoMonitoring(_cargo_pickups, company); +} + +/** + * Clear all delivery cargo monitors. + * @param company clear all delivery monitors for this company or if #INVALID_OWNER + * is passed, all delivery monitors are cleared regardless of company. + */ +void ClearCargoDeliveryMonitoring(CompanyID company) +{ + ClearCargoMonitoring(_cargo_deliveries, company); +} + +/** + * Get and reset the amount associated with a cargo monitor. + * @param[in,out] monitor_map Monitoring map to search (and reset for the queried entry). + * @param monitor Cargo monitor to query/reset. + * @param keep_monitoring After returning from this call, continue monitoring. + * @return Amount collected since last query/activation for the monitored combination. + */ +static int32 GetAmount(CargoMonitorMap &monitor_map, CargoMonitorID monitor, bool keep_monitoring) +{ + CargoMonitorMap::iterator iter = monitor_map.find(monitor); + if (iter == monitor_map.end()) { + if (keep_monitoring) { + std::pair p(monitor, 0); + monitor_map.insert(p); + } + return 0; + } else { + int32 result = iter->second; + iter->second = 0; + if (!keep_monitoring) monitor_map.erase(iter); + return result; + } +} + +/** + * Get the amount of cargo delivered for the given cargo monitor since activation or last query. + * @param monitor Cargo monitor to query. + * @param keep_monitoring After returning from this call, continue monitoring. + * @return Amount of delivered cargo for the monitored combination. + */ +int32 GetDeliveryAmount(CargoMonitorID monitor, bool keep_monitoring) +{ + return GetAmount(_cargo_deliveries, monitor, keep_monitoring); +} + +/** + * Get the amount of cargo picked up for the given cargo monitor since activation or last query. + * @param monitor Monitoring number to query. + * @param keep_monitoring After returning from this call, continue monitoring. + * @return Amount of picked up cargo for the monitored combination. + * @note Cargo pick up is counted on final delivery, to prevent users getting credit for picking up cargo without delivering it. + */ +int32 GetPickupAmount(CargoMonitorID monitor, bool keep_monitoring) +{ + return GetAmount(_cargo_pickups, monitor, keep_monitoring); +} + +/** + * Cargo was delivered to its final destination, update the pickup and delivery maps. + * @param cargo_type type of cargo. + * @param company company delivering the cargo. + * @param amount Amount of cargo delivered. + * @param src_type type of \a src. + * @param src index of source. + * @param st station where the cargo is delivered to. + */ +void AddCargoDelivery(CargoID cargo_type, CompanyID company, uint32 amount, SourceType src_type, SourceID src, const Station *st) +{ + if (amount == 0) return; + + if (src != INVALID_SOURCE) { + /* Handle pickup update. */ + switch (src_type) { + case ST_INDUSTRY: { + CargoMonitorID num = EncodeCargoIndustryMonitor(company, cargo_type, src); + CargoMonitorMap::iterator iter = _cargo_pickups.find(num); + if (iter != _cargo_pickups.end()) iter->second += amount; + break; + } + case ST_TOWN: { + CargoMonitorID num = EncodeCargoTownMonitor(company, cargo_type, src); + CargoMonitorMap::iterator iter = _cargo_pickups.find(num); + if (iter != _cargo_pickups.end()) iter->second += amount; + break; + } + default: break; + } + } + + /* Handle delivery. + * Note that delivery in the right area is sufficient to prevent trouble with neighbouring industries or houses. */ + + /* Town delivery. */ + CargoMonitorID num = EncodeCargoTownMonitor(company, cargo_type, st->town->index); + CargoMonitorMap::iterator iter = _cargo_deliveries.find(num); + if (iter != _cargo_deliveries.end()) iter->second += amount; + + /* Industry delivery. */ + for (const Industry * const *ip = st->industries_near.Begin(); ip != st->industries_near.End(); ip++) { + CargoMonitorID num = EncodeCargoIndustryMonitor(company, cargo_type, (*ip)->index); + CargoMonitorMap::iterator iter = _cargo_deliveries.find(num); + if (iter != _cargo_deliveries.end()) iter->second += amount; + } +} + diff --git a/src/cargomonitor.h b/src/cargomonitor.h new file mode 100644 index 0000000..061a182 --- /dev/null +++ b/src/cargomonitor.h @@ -0,0 +1,149 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file cargomonitor.h Cargo transport monitoring declarations. */ + +#ifndef CARGOMONITOR_H +#define CARGOMONITOR_H + +#include "cargo_type.h" +#include "company_func.h" +#include "industry.h" +#include "town.h" +#include "core/overflowsafe_type.hpp" +#include + +struct Station; + +/** + * Unique number for a company / cargo type / (town or industry). + * Encoding is as follows: + * - bits 0-15 town or industry number + * - bit 16 is set if it is an industry number (else it is a town number). + * - bits 19-23 Cargo type. + * - bits 24-31 %Company number. + */ +typedef uint32 CargoMonitorID; ///< Type of the cargo monitor number. + +/** Map type for storing and updating active cargo monitor numbers and their amounts. */ +typedef std::map CargoMonitorMap; + +extern CargoMonitorMap _cargo_pickups; +extern CargoMonitorMap _cargo_deliveries; + + +/** Constants for encoding and extracting cargo monitors. */ +enum CargoCompanyBits { + CCB_TOWN_IND_NUMBER_START = 0, ///< Start bit of the town or industry number. + CCB_TOWN_IND_NUMBER_LENGTH = 16, ///< Number of bits of the town or industry number. + CCB_IS_INDUSTRY_BIT = 16, ///< Bit indicating the town/industry number is an industry. + CCB_IS_INDUSTRY_BIT_VALUE = 1ul << CCB_IS_INDUSTRY_BIT, ///< Value of the #CCB_IS_INDUSTRY_BIT bit. + CCB_CARGO_TYPE_START = 19, ///< Start bit of the cargo type field. + CCB_CARGO_TYPE_LENGTH = 5, ///< Number of bits of the cargo type field. + CCB_COMPANY_START = 24, ///< Start bit of the company field. + CCB_COMPANY_LENGTH = 8, ///< Number of bits of the company field. +}; + + +/** + * Encode a cargo monitor for pickup or delivery at an industry. + * @param company Company performing the transport. + * @param ctype Cargo type being transported. + * @param ind %Industry providing or accepting the cargo. + * @return The encoded cargo/company/industry number. + */ +static inline CargoMonitorID EncodeCargoIndustryMonitor(CompanyID company, CargoID ctype, IndustryID ind) +{ + assert(ctype < (1 << CCB_CARGO_TYPE_LENGTH)); + + uint32 ret = 0; + SB(ret, CCB_TOWN_IND_NUMBER_START, CCB_TOWN_IND_NUMBER_LENGTH, ind); + SetBit(ret, CCB_IS_INDUSTRY_BIT); + SB(ret, CCB_CARGO_TYPE_START, CCB_CARGO_TYPE_LENGTH, ctype); + SB(ret, CCB_COMPANY_START, CCB_COMPANY_LENGTH, company); + return ret; +} + +/** + * Encode a cargo monitoring number for pickup or delivery at a town. + * @param company %Company performing the transport. + * @param ctype Cargo type being transported. + * @param town %Town providing or accepting the cargo. + * @return The encoded cargo/company/town number. + */ +static inline CargoMonitorID EncodeCargoTownMonitor(CompanyID company, CargoID ctype, TownID town) +{ + assert(ctype < (1 << CCB_CARGO_TYPE_LENGTH)); + + uint32 ret = 0; + SB(ret, CCB_TOWN_IND_NUMBER_START, CCB_TOWN_IND_NUMBER_LENGTH, town); + SB(ret, CCB_CARGO_TYPE_START, CCB_CARGO_TYPE_LENGTH, ctype); + SB(ret, CCB_COMPANY_START, CCB_COMPANY_LENGTH, company); + return ret; +} + +/** + * Extract the company from the cargo monitor. + * @param num Cargo monitoring number to decode. + * @return The extracted company id. + */ +static inline CompanyID DecodeMonitorCompany(CargoMonitorID num) +{ + return static_cast(GB(num, CCB_COMPANY_START, CCB_COMPANY_LENGTH)); +} + +/** + * Extract the cargo type from the cargo monitor. + * @param num Cargo monitoring number to decode. + * @return The extracted cargo type. + */ +static inline CargoID DecodeMonitorCargoType(CargoMonitorID num) +{ + return GB(num, CCB_CARGO_TYPE_START, CCB_CARGO_TYPE_LENGTH); +} + +/** + * Does the cargo number monitor an industry or a town? + * @param num Cargo monitoring number to decode. + * @return true if monitoring an industry, false if monitoring a town. + */ +static inline bool MonitorMonitorsIndustry(CargoMonitorID num) +{ + return HasBit(num, CCB_IS_INDUSTRY_BIT); +} + +/** + * Extract the industry number from the cargo monitor. + * @param num Cargo monitoring number to decode. + * @return The extracted industry id, or #INVALID_INDUSTRY if the number does not monitor an industry. + */ +static inline IndustryID DecodeMonitorIndustry(CargoMonitorID num) +{ + if (!MonitorMonitorsIndustry(num)) return INVALID_INDUSTRY; + return GB(num, CCB_TOWN_IND_NUMBER_START, CCB_TOWN_IND_NUMBER_LENGTH); +} + +/** + * Extract the town number from the cargo monitor. + * @param num Cargo monitoring number to decode. + * @return The extracted town id, or #INVALID_TOWN if the number does not monitor a town. + */ +static inline TownID DecodeMonitorTown(CargoMonitorID num) +{ + if (MonitorMonitorsIndustry(num)) return INVALID_TOWN; + return GB(num, CCB_TOWN_IND_NUMBER_START, CCB_TOWN_IND_NUMBER_LENGTH); +} + +void ClearCargoPickupMonitoring(CompanyID company = INVALID_OWNER); +void ClearCargoDeliveryMonitoring(CompanyID company = INVALID_OWNER); +int32 GetDeliveryAmount(CargoMonitorID monitor, bool keep_monitoring); +int32 GetPickupAmount(CargoMonitorID monitor, bool keep_monitoring); +void AddCargoDelivery(CargoID cargo_type, CompanyID company, uint32 amount, SourceType src_type, SourceID src, const Station *st); + +#endif /* CARGOMONITOR_H */ diff --git a/src/cargopacket.cpp b/src/cargopacket.cpp new file mode 100644 index 0000000..9b96be6 --- /dev/null +++ b/src/cargopacket.cpp @@ -0,0 +1,874 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file cargopacket.cpp Implementation of the cargo packets. */ + +#include "stdafx.h" +#include "station_base.h" +#include "core/pool_func.hpp" +#include "core/random_func.hpp" +#include "economy_base.h" +#include "cargoaction.h" +#include "order_type.h" + +#include "safeguards.h" + +/* Initialize the cargopacket-pool */ +CargoPacketPool _cargopacket_pool("CargoPacket"); +INSTANTIATE_POOL_METHODS(CargoPacket) + +/** + * Create a new packet for savegame loading. + */ +CargoPacket::CargoPacket() +{ + this->source_type = ST_INDUSTRY; + this->source_id = INVALID_SOURCE; +} + +/** + * Creates a new cargo packet. + * @param source Source station of the packet. + * @param source_xy Source location of the packet. + * @param count Number of cargo entities to put in this packet. + * @param source_type 'Type' of source the packet comes from (for subsidies). + * @param source_id Actual source of the packet (for subsidies). + * @pre count != 0 + * @note We have to zero memory ourselves here because we are using a 'new' + * that, in contrary to all other pools, does not memset to 0. + */ +CargoPacket::CargoPacket(StationID source, TileIndex source_xy, uint16 count, SourceType source_type, SourceID source_id) : + feeder_share(0), + count(count), + days_in_transit(0), + source_id(source_id), + source(source), + source_xy(source_xy), + loaded_at_xy(0) +{ + assert(count != 0); + this->source_type = source_type; +} + +/** + * Creates a new cargo packet. Initializes the fields that cannot be changed later. + * Used when loading or splitting packets. + * @param count Number of cargo entities to put in this packet. + * @param days_in_transit Number of days the cargo has been in transit. + * @param source Station the cargo was initially loaded. + * @param source_xy Station location the cargo was initially loaded. + * @param loaded_at_xy Location the cargo was loaded last. + * @param feeder_share Feeder share the packet has already accumulated. + * @param source_type 'Type' of source the packet comes from (for subsidies). + * @param source_id Actual source of the packet (for subsidies). + * @note We have to zero memory ourselves here because we are using a 'new' + * that, in contrary to all other pools, does not memset to 0. + */ +CargoPacket::CargoPacket(uint16 count, byte days_in_transit, StationID source, TileIndex source_xy, TileIndex loaded_at_xy, Money feeder_share, SourceType source_type, SourceID source_id) : + feeder_share(feeder_share), + count(count), + days_in_transit(days_in_transit), + source_id(source_id), + source(source), + source_xy(source_xy), + loaded_at_xy(loaded_at_xy) +{ + assert(count != 0); + this->source_type = source_type; +} + +/** + * Split this packet in two and return the split off part. + * @param new_size Size of the split part. + * @return Split off part, or NULL if no packet could be allocated! + */ +CargoPacket *CargoPacket::Split(uint new_size) +{ + if (!CargoPacket::CanAllocateItem()) return NULL; + + Money fs = this->FeederShare(new_size); + CargoPacket *cp_new = new CargoPacket(new_size, this->days_in_transit, this->source, this->source_xy, this->loaded_at_xy, fs, this->source_type, this->source_id); + this->feeder_share -= fs; + this->count -= new_size; + return cp_new; +} + +/** + * Merge another packet into this one. + * @param cp Packet to be merged in. + */ +void CargoPacket::Merge(CargoPacket *cp) +{ + this->count += cp->count; + this->feeder_share += cp->feeder_share; + delete cp; +} + +/** + * Reduce the packet by the given amount and remove the feeder share. + * @param count Amount to be removed. + */ +void CargoPacket::Reduce(uint count) +{ + assert(count < this->count); + this->feeder_share -= this->FeederShare(count); + this->count -= count; +} + +/** + * Invalidates (sets source_id to INVALID_SOURCE) all cargo packets from given source. + * @param src_type Type of source. + * @param src Index of source. + */ +/* static */ void CargoPacket::InvalidateAllFrom(SourceType src_type, SourceID src) +{ + CargoPacket *cp; + FOR_ALL_CARGOPACKETS(cp) { + if (cp->source_type == src_type && cp->source_id == src) cp->source_id = INVALID_SOURCE; + } +} + +/** + * Invalidates (sets source to INVALID_STATION) all cargo packets from given station. + * @param sid Station that gets removed. + */ +/* static */ void CargoPacket::InvalidateAllFrom(StationID sid) +{ + CargoPacket *cp; + FOR_ALL_CARGOPACKETS(cp) { + if (cp->source == sid) cp->source = INVALID_STATION; + } +} + +/* + * + * Cargo list implementation + * + */ + +/** + * Destroy the cargolist ("frees" all cargo packets). + */ +template +CargoList::~CargoList() +{ + for (Iterator it(this->packets.begin()); it != this->packets.end(); ++it) { + delete *it; + } +} + +/** + * Empty the cargo list, but don't free the cargo packets; + * the cargo packets are cleaned by CargoPacket's CleanPool. + */ +template +void CargoList::OnCleanPool() +{ + this->packets.clear(); +} + +/** + * Update the cached values to reflect the removal of this packet or part of it. + * Decreases count and days_in_transit. + * @param cp Packet to be removed from cache. + * @param count Amount of cargo from the given packet to be removed. + */ +template +void CargoList::RemoveFromCache(const CargoPacket *cp, uint count) +{ + assert(count <= cp->count); + this->count -= count; + this->cargo_days_in_transit -= cp->days_in_transit * count; +} + +/** + * Update the cache to reflect adding of this packet. + * Increases count and days_in_transit. + * @param cp New packet to be inserted. + */ +template +void CargoList::AddToCache(const CargoPacket *cp) +{ + this->count += cp->count; + this->cargo_days_in_transit += cp->days_in_transit * cp->count; +} + +/** Invalidates the cached data and rebuilds it. */ +template +void CargoList::InvalidateCache() +{ + this->count = 0; + this->cargo_days_in_transit = 0; + + for (ConstIterator it(this->packets.begin()); it != this->packets.end(); it++) { + static_cast(this)->AddToCache(*it); + } +} + +/** + * Tries to merge the second packet into the first and return if that was + * successful. + * @param icp Packet to be merged into. + * @param cp Packet to be eliminated. + * @return If the packets could be merged. + */ +template +/* static */ bool CargoList::TryMerge(CargoPacket *icp, CargoPacket *cp) +{ + if (Tinst::AreMergable(icp, cp) && + icp->count + cp->count <= CargoPacket::MAX_COUNT) { + icp->Merge(cp); + return true; + } else { + return false; + } +} + +/* + * + * Vehicle cargo list implementation. + * + */ + +/** + * Appends the given cargo packet. Tries to merge it with another one in the + * packets list. If no fitting packet is found, appends it. You can only append + * packets to the ranges of packets designated for keeping or loading. + * Furthermore if there are already packets reserved for loading you cannot + * directly add packets to the "keep" list. You first have to load the reserved + * ones. + * @warning After appending this packet may not exist anymore! + * @note Do not use the cargo packet anymore after it has been appended to this CargoList! + * @param cp Cargo packet to add. + * @param action Either MTA_KEEP if you want to add the packet directly or MTA_LOAD + * if you want to reserve it first. + * @pre cp != NULL + * @pre action == MTA_LOAD || (action == MTA_KEEP && this->designation_counts[MTA_LOAD] == 0) + */ +void VehicleCargoList::Append(CargoPacket *cp, MoveToAction action) +{ + assert(cp != NULL); + assert(action == MTA_LOAD || + (action == MTA_KEEP && this->action_counts[MTA_LOAD] == 0)); + this->AddToMeta(cp, action); + + if (this->count == cp->count) { + this->packets.push_back(cp); + return; + } + + uint sum = cp->count; + for (ReverseIterator it(this->packets.rbegin()); it != this->packets.rend(); it++) { + CargoPacket *icp = *it; + if (VehicleCargoList::TryMerge(icp, cp)) return; + sum += icp->count; + if (sum >= this->action_counts[action]) { + this->packets.push_back(cp); + return; + } + } + + NOT_REACHED(); +} + +/** + * Shifts cargo from the front of the packet list and applies some action to it. + * @tparam Taction Action class or function to be used. It should define + * "bool operator()(CargoPacket *)". If true is returned the + * cargo packet will be removed from the list. Otherwise it + * will be kept and the loop will be aborted. + * @param action Action instance to be applied. + */ +template +void VehicleCargoList::ShiftCargo(Taction action) +{ + Iterator it(this->packets.begin()); + while (it != this->packets.end() && action.MaxMove() > 0) { + CargoPacket *cp = *it; + if (action(cp)) { + it = this->packets.erase(it); + } else { + break; + } + } +} + +/** + * Pops cargo from the back of the packet list and applies some action to it. + * @tparam Taction Action class or function to be used. It should define + * "bool operator()(CargoPacket *)". If true is returned the + * cargo packet will be removed from the list. Otherwise it + * will be kept and the loop will be aborted. + * @param action Action instance to be applied. + */ +template +void VehicleCargoList::PopCargo(Taction action) +{ + if (this->packets.empty()) return; + Iterator it(--(this->packets.end())); + Iterator begin(this->packets.begin()); + while (action.MaxMove() > 0) { + CargoPacket *cp = *it; + if (action(cp)) { + if (it != begin) { + this->packets.erase(it--); + } else { + this->packets.erase(it); + break; + } + } else { + break; + } + } +} + +/** + * Update the cached values to reflect the removal of this packet or part of it. + * Decreases count, feeder share and days_in_transit. + * @param cp Packet to be removed from cache. + * @param count Amount of cargo from the given packet to be removed. + */ +void VehicleCargoList::RemoveFromCache(const CargoPacket *cp, uint count) +{ + this->feeder_share -= cp->FeederShare(count); + this->Parent::RemoveFromCache(cp, count); +} + +/** + * Update the cache to reflect adding of this packet. + * Increases count, feeder share and days_in_transit. + * @param cp New packet to be inserted. + */ +void VehicleCargoList::AddToCache(const CargoPacket *cp) +{ + this->feeder_share += cp->feeder_share; + this->Parent::AddToCache(cp); +} + +/** + * Removes a packet or part of it from the metadata. + * @param cp Packet to be removed. + * @param action MoveToAction of the packet (for updating the counts). + * @param count Amount of cargo to be removed. + */ +void VehicleCargoList::RemoveFromMeta(const CargoPacket *cp, MoveToAction action, uint count) +{ + assert(count <= this->action_counts[action]); + this->AssertCountConsistency(); + this->RemoveFromCache(cp, count); + this->action_counts[action] -= count; + this->AssertCountConsistency(); +} + +/** + * Adds a packet to the metadata. + * @param cp Packet to be added. + * @param action MoveToAction of the packet. + */ +void VehicleCargoList::AddToMeta(const CargoPacket *cp, MoveToAction action) +{ + this->AssertCountConsistency(); + this->AddToCache(cp); + this->action_counts[action] += cp->count; + this->AssertCountConsistency(); +} + +/** + * Ages the all cargo in this list. + */ +void VehicleCargoList::AgeCargo() +{ + for (ConstIterator it(this->packets.begin()); it != this->packets.end(); it++) { + CargoPacket *cp = *it; + /* If we're at the maximum, then we can't increase no more. */ + if (cp->days_in_transit == 0xFF) continue; + + cp->days_in_transit++; + this->cargo_days_in_transit += cp->count; + } +} + +/** + * Sets loaded_at_xy to the current station for all cargo to be transfered. + * This is done when stopping or skipping while the vehicle is unloading. In + * that case the vehicle will get part of its transfer credits early and it may + * get more transfer credits than it's entitled to. + * @param xy New loaded_at_xy for the cargo. + */ +void VehicleCargoList::SetTransferLoadPlace(TileIndex xy) +{ + uint sum = 0; + for (Iterator it = this->packets.begin(); sum < this->action_counts[MTA_TRANSFER]; ++it) { + CargoPacket *cp = *it; + cp->loaded_at_xy = xy; + sum += cp->count; + } +} + +/** + * Choose action to be performed with the given cargo packet. + * @param cp The packet. + * @param cargo_next Next hop the cargo wants to pass. + * @param current_station Current station of the vehicle carrying the cargo. + * @param accepted If the cargo is accepted at the current station. + * @param next_station Next station(s) the vehicle may stop at. + * @return MoveToAction to be performed. + */ +/* static */ VehicleCargoList::MoveToAction VehicleCargoList::ChooseAction(const CargoPacket *cp, StationID cargo_next, + StationID current_station, bool accepted, StationIDStack next_station) +{ + if (cargo_next == INVALID_STATION) { + return (accepted && cp->source != current_station) ? MTA_DELIVER : MTA_KEEP; + } else if (cargo_next == current_station) { + return MTA_DELIVER; + } else if (next_station.Contains(cargo_next)) { + return MTA_KEEP; + } else { + return MTA_TRANSFER; + } +} + +/** + * Stages cargo for unloading. The cargo is sorted so that packets to be + * transferred, delivered or kept are in consecutive chunks in the list. At the + * same time the designation_counts are updated to reflect the size of those + * chunks. + * @param accepted If the cargo will be accepted at the station. + * @param current_station ID of the station. + * @param next_station ID of the station the vehicle will go to next. + * @param order_flags OrderUnloadFlags that will apply to the unload operation. + * @param ge GoodsEntry for getting the flows. + * @param payment Payment object for registering transfers. + * return If any cargo will be unloaded. + */ +bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationIDStack next_station, uint8 order_flags, const GoodsEntry *ge, CargoPayment *payment) +{ + this->AssertCountConsistency(); + assert(this->action_counts[MTA_LOAD] == 0); + this->action_counts[MTA_TRANSFER] = this->action_counts[MTA_DELIVER] = this->action_counts[MTA_KEEP] = 0; + Iterator deliver = this->packets.end(); + Iterator it = this->packets.begin(); + uint sum = 0; + + bool force_keep = (order_flags & OUFB_NO_UNLOAD) != 0; + bool force_unload = (order_flags & OUFB_UNLOAD) != 0; + bool force_transfer = (order_flags & (OUFB_TRANSFER | OUFB_UNLOAD)) != 0; + assert(this->count > 0 || it == this->packets.end()); + while (sum < this->count) { + CargoPacket *cp = *it; + + this->packets.erase(it++); + StationID cargo_next = INVALID_STATION; + MoveToAction action = MTA_LOAD; + if (force_keep) { + action = MTA_KEEP; + } else if (force_unload && accepted && cp->source != current_station) { + action = MTA_DELIVER; + } else if (force_transfer) { + action = MTA_TRANSFER; + /* We cannot send the cargo to any of the possible next hops and + * also not to the current station. */ + FlowStatMap::const_iterator flow_it(ge->flows.find(cp->source)); + if (flow_it == ge->flows.end()) { + cargo_next = INVALID_STATION; + } else { + FlowStat new_shares = flow_it->second; + new_shares.ChangeShare(current_station, INT_MIN); + StationIDStack excluded = next_station; + while (!excluded.IsEmpty() && !new_shares.GetShares()->empty()) { + new_shares.ChangeShare(excluded.Pop(), INT_MIN); + } + if (new_shares.GetShares()->empty()) { + cargo_next = INVALID_STATION; + } else { + cargo_next = new_shares.GetVia(); + } + } + } else { + /* Rewrite an invalid source station to some random other one to + * avoid keeping the cargo in the vehicle forever. */ + if (cp->source == INVALID_STATION && !ge->flows.empty()) { + cp->source = ge->flows.begin()->first; + } + bool restricted = false; + FlowStatMap::const_iterator flow_it(ge->flows.find(cp->source)); + if (flow_it == ge->flows.end()) { + cargo_next = INVALID_STATION; + } else { + cargo_next = flow_it->second.GetViaWithRestricted(restricted); + } + action = VehicleCargoList::ChooseAction(cp, cargo_next, current_station, accepted, next_station); + if (restricted && action == MTA_TRANSFER) { + /* If the flow is restricted we can't transfer to it. Choose an + * unrestricted one instead. */ + cargo_next = flow_it->second.GetVia(); + action = VehicleCargoList::ChooseAction(cp, cargo_next, current_station, accepted, next_station); + } + } + Money share; + switch (action) { + case MTA_KEEP: + this->packets.push_back(cp); + if (deliver == this->packets.end()) --deliver; + break; + case MTA_DELIVER: + this->packets.insert(deliver, cp); + break; + case MTA_TRANSFER: + this->packets.push_front(cp); + /* Add feeder share here to allow reusing field for next station. */ + share = payment->PayTransfer(cp, cp->count); + cp->AddFeederShare(share); + this->feeder_share += share; + cp->next_station = cargo_next; + break; + default: + NOT_REACHED(); + } + this->action_counts[action] += cp->count; + sum += cp->count; + } + this->AssertCountConsistency(); + return this->action_counts[MTA_DELIVER] > 0 || this->action_counts[MTA_TRANSFER] > 0; +} + +/** Invalidates the cached data and rebuild it. */ +void VehicleCargoList::InvalidateCache() +{ + this->feeder_share = 0; + this->Parent::InvalidateCache(); +} + +/** + * Moves some cargo from one designation to another. You can only move + * between adjacent designations. E.g. you can keep cargo that was previously + * reserved (MTA_LOAD), but you can't reserve cargo that's marked as to be + * delivered. Furthermore, as this method doesn't change the actual packets, + * you cannot move cargo from or to MTA_TRANSFER. You need a specialized + * template method for that. + * @tparam from Previous designation of cargo. + * @tparam to New designation of cargo. + * @param max_move Maximum amount of cargo to reassign. + * @return Amount of cargo actually reassigned. + */ +template +uint VehicleCargoList::Reassign(uint max_move, TileOrStationID) +{ + assert_tcompile(Tfrom != MTA_TRANSFER && Tto != MTA_TRANSFER); + assert_tcompile(Tfrom - Tto == 1 || Tto - Tfrom == 1); + max_move = min(this->action_counts[Tfrom], max_move); + this->action_counts[Tfrom] -= max_move; + this->action_counts[Tto] += max_move; + return max_move; +} + +/** + * Reassign cargo from MTA_DELIVER to MTA_TRANSFER and take care of the next + * station the cargo wants to visit. + * @param max_move Maximum amount of cargo to reassign. + * @param next_station Station to record as next hop in the reassigned packets. + * @return Amount of cargo actually reassigned. + */ +template<> +uint VehicleCargoList::Reassign(uint max_move, TileOrStationID next_station) +{ + max_move = min(this->action_counts[MTA_DELIVER], max_move); + + uint sum = 0; + for (Iterator it(this->packets.begin()); sum < this->action_counts[MTA_TRANSFER] + max_move;) { + CargoPacket *cp = *it++; + sum += cp->Count(); + if (sum <= this->action_counts[MTA_TRANSFER]) continue; + if (sum > this->action_counts[MTA_TRANSFER] + max_move) { + CargoPacket *cp_split = cp->Split(sum - this->action_counts[MTA_TRANSFER] + max_move); + sum -= cp_split->Count(); + this->packets.insert(it, cp_split); + } + cp->next_station = next_station; + } + + this->action_counts[MTA_DELIVER] -= max_move; + this->action_counts[MTA_TRANSFER] += max_move; + return max_move; +} + +/** + * Returns reserved cargo to the station and removes it from the cache. + * @param max_move Maximum amount of cargo to move. + * @param dest Station the cargo is returned to. + * @param ID of next the station the cargo wants to go next. + * @return Amount of cargo actually returned. + */ +uint VehicleCargoList::Return(uint max_move, StationCargoList *dest, StationID next) +{ + max_move = min(this->action_counts[MTA_LOAD], max_move); + this->PopCargo(CargoReturn(this, dest, max_move, next)); + return max_move; +} + +/** + * Shifts cargo between two vehicles. + * @param dest Other vehicle's cargo list. + * @param max_move Maximum amount of cargo to be moved. + * @return Amount of cargo actually moved. + */ +uint VehicleCargoList::Shift(uint max_move, VehicleCargoList *dest) +{ + max_move = min(this->count, max_move); + this->PopCargo(CargoShift(this, dest, max_move)); + return max_move; +} + +/** + * Unloads cargo at the given station. Deliver or transfer, depending on the + * ranges defined by designation_counts. + * @param dest StationCargoList to add transferred cargo to. + * @param max_move Maximum amount of cargo to move. + * @param payment Payment object to register payments in. + * @return Amount of cargo actually unloaded. + */ +uint VehicleCargoList::Unload(uint max_move, StationCargoList *dest, CargoPayment *payment) +{ + uint moved = 0; + if (this->action_counts[MTA_TRANSFER] > 0) { + uint move = min(this->action_counts[MTA_TRANSFER], max_move); + this->ShiftCargo(CargoTransfer(this, dest, move)); + moved += move; + } + if (this->action_counts[MTA_TRANSFER] == 0 && this->action_counts[MTA_DELIVER] > 0 && moved < max_move) { + uint move = min(this->action_counts[MTA_DELIVER], max_move - moved); + this->ShiftCargo(CargoDelivery(this, move, payment)); + moved += move; + } + return moved; +} + +/** + * Truncates the cargo in this list to the given amount. It leaves the + * first cargo entities and removes max_move from the back of the list. + * @param max_move Maximum amount of entities to be removed from the list. + * @return Amount of entities actually moved. + */ +uint VehicleCargoList::Truncate(uint max_move) +{ + max_move = min(this->count, max_move); + this->PopCargo(CargoRemoval(this, max_move)); + return max_move; +} + +/** + * Routes packets with station "avoid" as next hop to a different place. + * @param max_move Maximum amount of cargo to move. + * @param dest List to prepend the cargo to. + * @param avoid Station to exclude from routing and current next hop of packets to reroute. + * @param avoid2 Additional station to exclude from routing. + * @oaram ge GoodsEntry to get the routing info from. + */ +uint VehicleCargoList::Reroute(uint max_move, VehicleCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge) +{ + max_move = min(this->action_counts[MTA_TRANSFER], max_move); + this->ShiftCargo(VehicleCargoReroute(this, dest, max_move, avoid, avoid2, ge)); + return max_move; +} + +/* + * + * Station cargo list implementation. + * + */ + +/** + * Appends the given cargo packet to the range of packets with the same next station + * @warning After appending this packet may not exist anymore! + * @note Do not use the cargo packet anymore after it has been appended to this CargoList! + * @param next the next hop + * @param cp the cargo packet to add + * @pre cp != NULL + */ +void StationCargoList::Append(CargoPacket *cp, StationID next) +{ + assert(cp != NULL); + this->AddToCache(cp); + + StationCargoPacketMap::List &list = this->packets[next]; + for (StationCargoPacketMap::List::reverse_iterator it(list.rbegin()); + it != list.rend(); it++) { + if (StationCargoList::TryMerge(*it, cp)) return; + } + + /* The packet could not be merged with another one */ + list.push_back(cp); +} + +/** + * Shifts cargo from the front of the packet list for a specific station and + * applies some action to it. + * @tparam Taction Action class or function to be used. It should define + * "bool operator()(CargoPacket *)". If true is returned the + * cargo packet will be removed from the list. Otherwise it + * will be kept and the loop will be aborted. + * @param action Action instance to be applied. + * @param next Next hop the cargo wants to visit. + * @return True if all packets with the given next hop have been removed, + * False otherwise. + */ +template +bool StationCargoList::ShiftCargo(Taction &action, StationID next) +{ + std::pair range(this->packets.equal_range(next)); + for (Iterator it(range.first); it != range.second && it.GetKey() == next;) { + if (action.MaxMove() == 0) return false; + CargoPacket *cp = *it; + if (action(cp)) { + it = this->packets.erase(it); + } else { + return false; + } + } + return true; +} + +/** + * Shifts cargo from the front of the packet list for a specific station and + * and optional also from the list for "any station", then applies some action + * to it. + * @tparam Taction Action class or function to be used. It should define + * "bool operator()(CargoPacket *)". If true is returned the + * cargo packet will be removed from the list. Otherwise it + * will be kept and the loop will be aborted. + * @param action Action instance to be applied. + * @param next Next hop the cargo wants to visit. + * @param include_invalid If cargo from the INVALID_STATION list should be + * used if necessary. + * @return Amount of cargo actually moved. + */ +template +uint StationCargoList::ShiftCargo(Taction action, StationIDStack next, bool include_invalid) +{ + uint max_move = action.MaxMove(); + while (!next.IsEmpty()) { + this->ShiftCargo(action, next.Pop()); + if (action.MaxMove() == 0) break; + } + if (include_invalid && action.MaxMove() > 0) { + this->ShiftCargo(action, INVALID_STATION); + } + return max_move - action.MaxMove(); +} + +/** + * Truncates where each destination loses roughly the same percentage of its + * cargo. This is done by randomizing the selection of packets to be removed. + * Optionally count the cargo by origin station. + * @param max_move Maximum amount of cargo to remove. + * @param cargo_per_source Container for counting the cargo by origin. + * @return Amount of cargo actually moved. + */ +uint StationCargoList::Truncate(uint max_move, StationCargoAmountMap *cargo_per_source) +{ + max_move = min(max_move, this->count); + uint prev_count = this->count; + uint moved = 0; + uint loop = 0; + bool do_count = cargo_per_source != NULL; + while (max_move > moved) { + for (Iterator it(this->packets.begin()); it != this->packets.end();) { + CargoPacket *cp = *it; + if (prev_count > max_move && RandomRange(prev_count) < prev_count - max_move) { + if (do_count && loop == 0) { + (*cargo_per_source)[cp->source] += cp->count; + } + ++it; + continue; + } + uint diff = max_move - moved; + if (cp->count > diff) { + if (diff > 0) { + this->RemoveFromCache(cp, diff); + cp->Reduce(diff); + moved += diff; + } + if (loop > 0) { + if (do_count) (*cargo_per_source)[cp->source] -= diff; + return moved; + } else { + if (do_count) (*cargo_per_source)[cp->source] += cp->count; + ++it; + } + } else { + it = this->packets.erase(it); + if (do_count && loop > 0) { + (*cargo_per_source)[cp->source] -= cp->count; + } + moved += cp->count; + this->RemoveFromCache(cp, cp->count); + delete cp; + } + } + loop++; + } + return moved; +} + +/** + * Reserves cargo for loading onto the vehicle. + * @param max_move Maximum amount of cargo to reserve. + * @param dest VehicleCargoList to reserve for. + * @param load_place Tile index of the current station. + * @param next_station Next station(s) the loading vehicle will visit. + * @return Amount of cargo actually reserved. + */ +uint StationCargoList::Reserve(uint max_move, VehicleCargoList *dest, TileIndex load_place, StationIDStack next_station) +{ + return this->ShiftCargo(CargoReservation(this, dest, max_move, load_place), next_station, true); +} + +/** + * Loads cargo onto a vehicle. If the vehicle has reserved cargo load that. + * Otherwise load cargo from the station. + * @param max_move Amount of cargo to load. + * @param dest Vehicle cargo list where the cargo resides. + * @param load_place The new loaded_at_xy to be assigned to packets being moved. + * @param next_station Next station(s) the loading vehicle will visit. + * @return Amount of cargo actually loaded. + * @note Vehicles may or may not reserve, depending on their orders. The two + * modes of loading are exclusive, though. If cargo is reserved we don't + * need to load unreserved cargo. + */ +uint StationCargoList::Load(uint max_move, VehicleCargoList *dest, TileIndex load_place, StationIDStack next_station) +{ + uint move = min(dest->ActionCount(VehicleCargoList::MTA_LOAD), max_move); + if (move > 0) { + this->reserved_count -= move; + dest->Reassign(move); + return move; + } else { + return this->ShiftCargo(CargoLoad(this, dest, max_move, load_place), next_station, true); + } +} + +/** + * Routes packets with station "avoid" as next hop to a different place. + * @param max_move Maximum amount of cargo to move. + * @param dest List to append the cargo to. + * @param avoid Station to exclude from routing and current next hop of packets to reroute. + * @param avoid2 Additional station to exclude from routing. + * @oaram ge GoodsEntry to get the routing info from. + */ +uint StationCargoList::Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge) +{ + return this->ShiftCargo(StationCargoReroute(this, dest, max_move, avoid, avoid2, ge), avoid, false); +} + +/* + * We have to instantiate everything we want to be usable. + */ +template class CargoList; +template class CargoList; +template uint VehicleCargoList::Reassign(uint, TileOrStationID); diff --git a/src/cargopacket.h b/src/cargopacket.h new file mode 100644 index 0000000..0ed4fd9 --- /dev/null +++ b/src/cargopacket.h @@ -0,0 +1,571 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file cargopacket.h Base class for cargo packets. */ + +#ifndef CARGOPACKET_H +#define CARGOPACKET_H + +#include "core/pool_type.hpp" +#include "economy_type.h" +#include "station_type.h" +#include "order_type.h" +#include "cargo_type.h" +#include "vehicle_type.h" +#include "core/multimap.hpp" +#include + +/** Unique identifier for a single cargo packet. */ +typedef uint32 CargoPacketID; +struct CargoPacket; + +/** Type of the pool for cargo packets for a little over 16 million packets. */ +typedef Pool CargoPacketPool; +/** The actual pool with cargo packets. */ +extern CargoPacketPool _cargopacket_pool; + +struct GoodsEntry; // forward-declare for Stage() and RerouteStalePackets() + +template class CargoList; +class StationCargoList; // forward-declare, so we can use it in VehicleCargoList. +extern const struct SaveLoad *GetCargoPacketDesc(); + +typedef uint32 TileOrStationID; + +/** + * Container for cargo from the same location and time. + */ +struct CargoPacket : CargoPacketPool::PoolItem<&_cargopacket_pool> { +private: + Money feeder_share; ///< Value of feeder pickup to be paid for on delivery of cargo. + uint16 count; ///< The amount of cargo in this packet. + byte days_in_transit; ///< Amount of days this packet has been in transit. + SourceTypeByte source_type; ///< Type of \c source_id. + SourceID source_id; ///< Index of source, INVALID_SOURCE if unknown/invalid. + StationID source; ///< The station where the cargo came from first. + TileIndex source_xy; ///< The origin of the cargo (first station in feeder chain). + union { + TileOrStationID loaded_at_xy; ///< Location where this cargo has been loaded into the vehicle. + TileOrStationID next_station; ///< Station where the cargo wants to go next. + }; + + /** The CargoList caches, thus needs to know about it. */ + template friend class CargoList; + friend class VehicleCargoList; + friend class StationCargoList; + /** We want this to be saved, right? */ + friend const struct SaveLoad *GetCargoPacketDesc(); +public: + /** Maximum number of items in a single cargo packet. */ + static const uint16 MAX_COUNT = UINT16_MAX; + + CargoPacket(); + CargoPacket(StationID source, TileIndex source_xy, uint16 count, SourceType source_type, SourceID source_id); + CargoPacket(uint16 count, byte days_in_transit, StationID source, TileIndex source_xy, TileIndex loaded_at_xy, Money feeder_share = 0, SourceType source_type = ST_INDUSTRY, SourceID source_id = INVALID_SOURCE); + + /** Destroy the packet. */ + ~CargoPacket() { } + + CargoPacket *Split(uint new_size); + void Merge(CargoPacket *cp); + void Reduce(uint count); + + /** + * Sets the tile where the packet was loaded last. + * @param load_place Tile where the packet was loaded last. + */ + void SetLoadPlace(TileIndex load_place) { this->loaded_at_xy = load_place; } + + /** + * Sets the station where the packet is supposed to go next. + * @param next_station Next station the packet should go to. + */ + void SetNextStation(StationID next_station) { this->next_station = next_station; } + + /** + * Adds some feeder share to the packet. + * @param new_share Feeder share to be added. + */ + void AddFeederShare(Money new_share) { this->feeder_share += new_share; } + + /** + * Gets the number of 'items' in this packet. + * @return Item count. + */ + inline uint16 Count() const + { + return this->count; + } + + /** + * Gets the amount of money already paid to earlier vehicles in + * the feeder chain. + * @return Feeder share. + */ + inline Money FeederShare() const + { + return this->feeder_share; + } + + /** + * Gets part of the amount of money already paid to earlier vehicles in + * the feeder chain. + * @param part Amount of cargo to get the share for. + * @return Feeder share for the given amount of cargo. + */ + inline Money FeederShare(uint part) const + { + return this->feeder_share * part / static_cast(this->count); + } + + /** + * Gets the number of days this cargo has been in transit. + * This number isn't really in days, but in 2.5 days (CARGO_AGING_TICKS = 185 ticks) and + * it is capped at 255. + * @return Length this cargo has been in transit. + */ + inline byte DaysInTransit() const + { + return this->days_in_transit; + } + + /** + * Gets the type of the cargo's source. industry, town or head quarter. + * @return Source type. + */ + inline SourceType SourceSubsidyType() const + { + return this->source_type; + } + + /** + * Gets the ID of the cargo's source. An IndustryID, TownID or CompanyID. + * @return Source ID. + */ + inline SourceID SourceSubsidyID() const + { + return this->source_id; + } + + /** + * Gets the ID of the station where the cargo was loaded for the first time. + * @return StationID. + */ + inline StationID SourceStation() const + { + return this->source; + } + + /** + * Gets the coordinates of the cargo's source station. + * @return Source station's coordinates. + */ + inline TileIndex SourceStationXY() const + { + return this->source_xy; + } + + /** + * Gets the coordinates of the cargo's last loading station. + * @return Last loading station's coordinates. + */ + inline TileIndex LoadedAtXY() const + { + return this->loaded_at_xy; + } + + /** + * Gets the ID of station the cargo wants to go next. + * @return Next station for this packets. + */ + inline StationID NextStation() const + { + return this->next_station; + } + + static void InvalidateAllFrom(SourceType src_type, SourceID src); + static void InvalidateAllFrom(StationID sid); + static void AfterLoad(); +}; + +/** + * Iterate over all _valid_ cargo packets from the given start. + * @param var Variable used as "iterator". + * @param start Cargo packet ID of the first packet to iterate over. + */ +#define FOR_ALL_CARGOPACKETS_FROM(var, start) FOR_ALL_ITEMS_FROM(CargoPacket, cargopacket_index, var, start) + +/** + * Iterate over all _valid_ cargo packets from the begin of the pool. + * @param var Variable used as "iterator". + */ +#define FOR_ALL_CARGOPACKETS(var) FOR_ALL_CARGOPACKETS_FROM(var, 0) + +/** + * Simple collection class for a list of cargo packets. + * @tparam Tinst Actual instantiation of this cargo list. + */ +template +class CargoList { +public: + /** The iterator for our container. */ + typedef typename Tcont::iterator Iterator; + /** The reverse iterator for our container. */ + typedef typename Tcont::reverse_iterator ReverseIterator; + /** The const iterator for our container. */ + typedef typename Tcont::const_iterator ConstIterator; + /** The const reverse iterator for our container. */ + typedef typename Tcont::const_reverse_iterator ConstReverseIterator; + + /** Kind of actions that could be done with packets on move. */ + enum MoveToAction { + MTA_BEGIN = 0, + MTA_TRANSFER = 0, ///< Transfer the cargo to the station. + MTA_DELIVER, ///< Deliver the cargo to some town or industry. + MTA_KEEP, ///< Keep the cargo in the vehicle. + MTA_LOAD, ///< Load the cargo from the station. + MTA_END, + NUM_MOVE_TO_ACTION = MTA_END + }; + +protected: + uint count; ///< Cache for the number of cargo entities. + uint cargo_days_in_transit; ///< Cache for the sum of number of days in transit of each entity; comparable to man-hours. + + Tcont packets; ///< The cargo packets in this list. + + void AddToCache(const CargoPacket *cp); + + void RemoveFromCache(const CargoPacket *cp, uint count); + + static bool TryMerge(CargoPacket *cp, CargoPacket *icp); + +public: + /** Create the cargo list. */ + CargoList() {} + + ~CargoList(); + + void OnCleanPool(); + + /** + * Returns a pointer to the cargo packet list (so you can iterate over it etc). + * @return Pointer to the packet list. + */ + inline const Tcont *Packets() const + { + return &this->packets; + } + + /** + * Returns average number of days in transit for a cargo entity. + * @return The before mentioned number. + */ + inline uint DaysInTransit() const + { + return this->count == 0 ? 0 : this->cargo_days_in_transit / this->count; + } + + void InvalidateCache(); +}; + +typedef std::list CargoPacketList; + +/** + * CargoList that is used for vehicles. + */ +class VehicleCargoList : public CargoList { +protected: + /** The (direct) parent of this class. */ + typedef CargoList Parent; + + Money feeder_share; ///< Cache for the feeder share. + uint action_counts[NUM_MOVE_TO_ACTION]; ///< Counts of cargo to be transfered, delivered, kept and loaded. + + template + void ShiftCargo(Taction action); + + template + void PopCargo(Taction action); + + /** + * Assert that the designation counts add up. + */ + inline void AssertCountConsistency() const + { + assert(this->action_counts[MTA_KEEP] + + this->action_counts[MTA_DELIVER] + + this->action_counts[MTA_TRANSFER] + + this->action_counts[MTA_LOAD] == this->count); + } + + void AddToCache(const CargoPacket *cp); + void RemoveFromCache(const CargoPacket *cp, uint count); + + void AddToMeta(const CargoPacket *cp, MoveToAction action); + void RemoveFromMeta(const CargoPacket *cp, MoveToAction action, uint count); + + static MoveToAction ChooseAction(const CargoPacket *cp, StationID cargo_next, + StationID current_station, bool accepted, StationIDStack next_station); + +public: + /** The station cargo list needs to control the unloading. */ + friend class StationCargoList; + /** The super class ought to know what it's doing. */ + friend class CargoList; + /** The vehicles have a cargo list (and we want that saved). */ + friend const struct SaveLoad *GetVehicleDescription(VehicleType vt); + + friend class CargoShift; + friend class CargoTransfer; + friend class CargoDelivery; + template + friend class CargoRemoval; + friend class CargoReturn; + friend class VehicleCargoReroute; + + /** + * Returns source of the first cargo packet in this list. + * @return The before mentioned source. + */ + inline StationID Source() const + { + return this->count == 0 ? INVALID_STATION : this->packets.front()->source; + } + + /** + * Returns total sum of the feeder share for all packets. + * @return The before mentioned number. + */ + inline Money FeederShare() const + { + return this->feeder_share; + } + + /** + * Returns the amount of cargo designated for a given purpose. + * @param action Action the cargo is designated for. + * @return Amount of cargo designated for the given action. + */ + inline uint ActionCount(MoveToAction action) const + { + return this->action_counts[action]; + } + + /** + * Returns sum of cargo on board the vehicle (ie not only + * reserved). + * @return Cargo on board the vehicle. + */ + inline uint StoredCount() const + { + return this->count - this->action_counts[MTA_LOAD]; + } + + /** + * Returns sum of cargo, including reserved cargo. + * @return Sum of cargo. + */ + inline uint TotalCount() const + { + return this->count; + } + + /** + * Returns sum of reserved cargo. + * @return Sum of reserved cargo. + */ + inline uint ReservedCount() const + { + return this->action_counts[MTA_LOAD]; + } + + /** + * Returns sum of cargo to be moved out of the vehicle at the current station. + * @return Cargo to be moved. + */ + inline uint UnloadCount() const + { + return this->action_counts[MTA_TRANSFER] + this->action_counts[MTA_DELIVER]; + } + + /** + * Returns the sum of cargo to be kept in the vehicle at the current station. + * @return Cargo to be kept or loaded. + */ + inline uint RemainingCount() const + { + return this->action_counts[MTA_KEEP] + this->action_counts[MTA_LOAD]; + } + + void Append(CargoPacket *cp, MoveToAction action = MTA_KEEP); + + void AgeCargo(); + + void InvalidateCache(); + + void SetTransferLoadPlace(TileIndex xy); + + bool Stage(bool accepted, StationID current_station, StationIDStack next_station, uint8 order_flags, const GoodsEntry *ge, CargoPayment *payment); + + /** + * Marks all cargo in the vehicle as to be kept. This is mostly useful for + * loading old savegames. When loading is aborted the reserved cargo has + * to be returned first. + */ + inline void KeepAll() + { + this->action_counts[MTA_DELIVER] = this->action_counts[MTA_TRANSFER] = this->action_counts[MTA_LOAD] = 0; + this->action_counts[MTA_KEEP] = this->count; + } + + /* Methods for moving cargo around. First parameter is always maximum + * amount of cargo to be moved. Second parameter is destination (if + * applicable), return value is amount of cargo actually moved. */ + + template + uint Reassign(uint max_move, TileOrStationID update = INVALID_TILE); + uint Return(uint max_move, StationCargoList *dest, StationID next_station); + uint Unload(uint max_move, StationCargoList *dest, CargoPayment *payment); + uint Shift(uint max_move, VehicleCargoList *dest); + uint Truncate(uint max_move = UINT_MAX); + uint Reroute(uint max_move, VehicleCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge); + + /** + * Are two the two CargoPackets mergeable in the context of + * a list of CargoPackets for a Vehicle? + * @param cp1 First CargoPacket. + * @param cp2 Second CargoPacket. + * @return True if they are mergeable. + */ + static bool AreMergable(const CargoPacket *cp1, const CargoPacket *cp2) + { + return cp1->source_xy == cp2->source_xy && + cp1->days_in_transit == cp2->days_in_transit && + cp1->source_type == cp2->source_type && + cp1->source_id == cp2->source_id && + cp1->loaded_at_xy == cp2->loaded_at_xy; + } +}; + +typedef MultiMap StationCargoPacketMap; +typedef std::map StationCargoAmountMap; + +/** + * CargoList that is used for stations. + */ +class StationCargoList : public CargoList { +protected: + /** The (direct) parent of this class. */ + typedef CargoList Parent; + + uint reserved_count; ///< Amount of cargo being reserved for loading. + +public: + /** The super class ought to know what it's doing. */ + friend class CargoList; + /** The stations, via GoodsEntry, have a CargoList. */ + friend const struct SaveLoad *GetGoodsDesc(); + + friend class CargoLoad; + friend class CargoTransfer; + template + friend class CargoRemoval; + friend class CargoReservation; + friend class CargoReturn; + friend class StationCargoReroute; + + static void InvalidateAllFrom(SourceType src_type, SourceID src); + + template + bool ShiftCargo(Taction &action, StationID next); + + template + uint ShiftCargo(Taction action, StationIDStack next, bool include_invalid); + + void Append(CargoPacket *cp, StationID next); + + /** + * Check for cargo headed for a specific station. + * @param next Station the cargo is headed for. + * @return If there is any cargo for that station. + */ + inline bool HasCargoFor(StationIDStack next) const + { + while (!next.IsEmpty()) { + if (this->packets.find(next.Pop()) != this->packets.end()) return true; + } + /* Packets for INVALID_STTION can go anywhere. */ + return this->packets.find(INVALID_STATION) != this->packets.end(); + } + + /** + * Returns source of the first cargo packet in this list. + * @return The before mentioned source. + */ + inline StationID Source() const + { + return this->count == 0 ? INVALID_STATION : this->packets.begin()->second.front()->source; + } + + /** + * Returns sum of cargo still available for loading at the sation. + * (i.e. not counting cargo which is already reserved for loading) + * @return Cargo on board the vehicle. + */ + inline uint AvailableCount() const + { + return this->count; + } + + /** + * Returns sum of cargo reserved for loading onto vehicles. + * @return Cargo reserved for loading. + */ + inline uint ReservedCount() const + { + return this->reserved_count; + } + + /** + * Returns total count of cargo at the station, including + * cargo which is already reserved for loading. + * @return Total cargo count. + */ + inline uint TotalCount() const + { + return this->count + this->reserved_count; + } + + /* Methods for moving cargo around. First parameter is always maximum + * amount of cargo to be moved. Second parameter is destination (if + * applicable), return value is amount of cargo actually moved. */ + + uint Reserve(uint max_move, VehicleCargoList *dest, TileIndex load_place, StationIDStack next); + uint Load(uint max_move, VehicleCargoList *dest, TileIndex load_place, StationIDStack next); + uint Truncate(uint max_move = UINT_MAX, StationCargoAmountMap *cargo_per_source = NULL); + uint Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge); + + /** + * Are two the two CargoPackets mergeable in the context of + * a list of CargoPackets for a Vehicle? + * @param cp1 First CargoPacket. + * @param cp2 Second CargoPacket. + * @return True if they are mergeable. + */ + static bool AreMergable(const CargoPacket *cp1, const CargoPacket *cp2) + { + return cp1->source_xy == cp2->source_xy && + cp1->days_in_transit == cp2->days_in_transit && + cp1->source_type == cp2->source_type && + cp1->source_id == cp2->source_id; + } +}; + +#endif /* CARGOPACKET_H */ diff --git a/src/cargotype.cpp b/src/cargotype.cpp new file mode 100644 index 0000000..863c585 --- /dev/null +++ b/src/cargotype.cpp @@ -0,0 +1,195 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file cargotype.cpp Implementation of cargoes. */ + +#include "stdafx.h" +#include "cargotype.h" +#include "newgrf_cargo.h" +#include "string_func.h" +#include "strings_func.h" +#include "core/sort_func.hpp" + +#include "table/sprites.h" +#include "table/strings.h" +#include "table/cargo_const.h" + +#include "safeguards.h" + +CargoSpec CargoSpec::array[NUM_CARGO]; + +/** + * Bitmask of cargo types available. This includes phony cargoes like regearing cargoes. + * Initialized during a call to #SetupCargoForClimate. + */ +uint32 _cargo_mask; + +/** + * Bitmask of real cargo types available. Phony cargoes like regearing cargoes are excluded. + */ +uint32 _standard_cargo_mask; + +/** + * Set up the default cargo types for the given landscape type. + * @param l Landscape + */ +void SetupCargoForClimate(LandscapeID l) +{ + assert(l < lengthof(_default_climate_cargo)); + + /* Reset and disable all cargo types */ + memset(CargoSpec::array, 0, sizeof(CargoSpec::array)); + for (CargoID i = 0; i < lengthof(CargoSpec::array); i++) { + CargoSpec::Get(i)->bitnum = INVALID_CARGO; + + /* Set defaults for newer properties, which old GRFs do not know */ + CargoSpec::Get(i)->multiplier = 0x100; + } + + _cargo_mask = 0; + + for (CargoID i = 0; i < lengthof(_default_climate_cargo[l]); i++) { + CargoLabel cl = _default_climate_cargo[l][i]; + + /* Bzzt: check if cl is just an index into the cargo table */ + if (cl < lengthof(_default_cargo)) { + /* Copy the indexed cargo */ + CargoSpec *cargo = CargoSpec::Get(i); + *cargo = _default_cargo[cl]; + if (cargo->bitnum != INVALID_CARGO) SetBit(_cargo_mask, i); + continue; + } + + /* Loop through each of the default cargo types to see if + * the label matches */ + for (uint j = 0; j < lengthof(_default_cargo); j++) { + if (_default_cargo[j].label == cl) { + *CargoSpec::Get(i) = _default_cargo[j]; + + /* Populate the available cargo mask */ + SetBit(_cargo_mask, i); + break; + } + } + } +} + +/** + * Get the cargo ID by cargo label. + * @param cl Cargo type to get. + * @return ID number if the cargo exists, else #CT_INVALID + */ +CargoID GetCargoIDByLabel(CargoLabel cl) +{ + const CargoSpec *cs; + FOR_ALL_CARGOSPECS(cs) { + if (cs->label == cl) return cs->Index(); + } + + /* No matching label was found, so it is invalid */ + return CT_INVALID; +} + + +/** + * Find the CargoID of a 'bitnum' value. + * @param bitnum 'bitnum' to find. + * @return First CargoID with the given bitnum, or #CT_INVALID if not found or if the provided \a bitnum is invalid. + */ +CargoID GetCargoIDByBitnum(uint8 bitnum) +{ + if (bitnum == INVALID_CARGO) return CT_INVALID; + + const CargoSpec *cs; + FOR_ALL_CARGOSPECS(cs) { + if (cs->bitnum == bitnum) return cs->Index(); + } + + /* No matching label was found, so it is invalid */ + return CT_INVALID; +} + +/** + * Get sprite for showing cargo of this type. + * @return Sprite number to use. + */ +SpriteID CargoSpec::GetCargoIcon() const +{ + SpriteID sprite = this->sprite; + if (sprite == 0xFFFF) { + /* A value of 0xFFFF indicates we should draw a custom icon */ + sprite = GetCustomCargoSprite(this); + } + + if (sprite == 0) sprite = SPR_CARGO_GOODS; + + return sprite; +} + +const CargoSpec *_sorted_cargo_specs[NUM_CARGO]; ///< Cargo specifications sorted alphabetically by name. +uint8 _sorted_cargo_specs_size; ///< Number of cargo specifications stored at the _sorted_cargo_specs array (including special cargoes). +uint8 _sorted_standard_cargo_specs_size; ///< Number of standard cargo specifications stored at the _sorted_cargo_specs array. + + +/** Sort cargo specifications by their name. */ +static int CDECL CargoSpecNameSorter(const CargoSpec * const *a, const CargoSpec * const *b) +{ + static char a_name[64]; + static char b_name[64]; + + GetString(a_name, (*a)->name, lastof(a_name)); + GetString(b_name, (*b)->name, lastof(b_name)); + + int res = strnatcmp(a_name, b_name); // Sort by name (natural sorting). + + /* If the names are equal, sort by cargo bitnum. */ + return (res != 0) ? res : ((*a)->bitnum - (*b)->bitnum); +} + +/** Sort cargo specifications by their cargo class. */ +static int CDECL CargoSpecClassSorter(const CargoSpec * const *a, const CargoSpec * const *b) +{ + int res = ((*b)->classes & CC_PASSENGERS) - ((*a)->classes & CC_PASSENGERS); + if (res == 0) { + res = ((*b)->classes & CC_MAIL) - ((*a)->classes & CC_MAIL); + if (res == 0) { + res = ((*a)->classes & CC_SPECIAL) - ((*b)->classes & CC_SPECIAL); + if (res == 0) { + return CargoSpecNameSorter(a, b); + } + } + } + + return res; +} + +/** Initialize the list of sorted cargo specifications. */ +void InitializeSortedCargoSpecs() +{ + _sorted_cargo_specs_size = 0; + const CargoSpec *cargo; + /* Add each cargo spec to the list. */ + FOR_ALL_CARGOSPECS(cargo) { + _sorted_cargo_specs[_sorted_cargo_specs_size] = cargo; + _sorted_cargo_specs_size++; + } + + /* Sort cargo specifications by cargo class and name. */ + QSortT(_sorted_cargo_specs, _sorted_cargo_specs_size, &CargoSpecClassSorter); + + _standard_cargo_mask = 0; + + _sorted_standard_cargo_specs_size = 0; + FOR_ALL_SORTED_CARGOSPECS(cargo) { + if (cargo->classes & CC_SPECIAL) break; + _sorted_standard_cargo_specs_size++; + SetBit(_standard_cargo_mask, cargo->Index()); + } +} + diff --git a/src/cargotype.h b/src/cargotype.h new file mode 100644 index 0000000..fee461d --- /dev/null +++ b/src/cargotype.h @@ -0,0 +1,175 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file cargotype.h Types/functions related to cargoes. */ + +#ifndef CARGOTYPE_H +#define CARGOTYPE_H + +#include "economy_type.h" +#include "cargo_type.h" +#include "gfx_type.h" +#include "strings_type.h" +#include "landscape_type.h" + +/** Globally unique label of a cargo type. */ +typedef uint32 CargoLabel; + +/** Town growth effect when delivering cargo. */ +enum TownEffect { + TE_BEGIN = 0, + TE_NONE = TE_BEGIN, ///< Cargo has no effect. + TE_PASSENGERS, ///< Cargo behaves passenger-like. + TE_MAIL, ///< Cargo behaves mail-like. + TE_GOODS, ///< Cargo behaves goods/candy-like. + TE_WATER, ///< Cargo behaves water-like. + TE_FOOD, ///< Cargo behaves food/fizzy-drinks-like. + TE_END, ///< End of town effects. + NUM_TE = TE_END, ///< Amount of town effects. +}; + +/** Cargo classes. */ +enum CargoClass { + CC_NOAVAILABLE = 0, ///< No cargo class has been specified + CC_PASSENGERS = 1 << 0, ///< Passengers + CC_MAIL = 1 << 1, ///< Mail + CC_EXPRESS = 1 << 2, ///< Express cargo (Goods, Food, Candy, but also possible for passengers) + CC_ARMOURED = 1 << 3, ///< Armoured cargo (Valuables, Gold, Diamonds) + CC_BULK = 1 << 4, ///< Bulk cargo (Coal, Grain etc., Ores, Fruit) + CC_PIECE_GOODS = 1 << 5, ///< Piece goods (Livestock, Wood, Steel, Paper) + CC_LIQUID = 1 << 6, ///< Liquids (Oil, Water, Rubber) + CC_REFRIGERATED = 1 << 7, ///< Refrigerated cargo (Food, Fruit) + CC_HAZARDOUS = 1 << 8, ///< Hazardous cargo (Nuclear Fuel, Explosives, etc.) + CC_COVERED = 1 << 9, ///< Covered/Sheltered Freight (Transportation in Box Vans, Silo Wagons, etc.) + CC_SPECIAL = 1 << 15, ///< Special bit used for livery refit tricks instead of normal cargoes. +}; + +static const byte INVALID_CARGO = 0xFF; ///< Constant representing invalid cargo + +/** Specification of a cargo type. */ +struct CargoSpec { + uint8 bitnum; ///< Cargo bit number, is #INVALID_CARGO for a non-used spec. + CargoLabel label; ///< Unique label of the cargo type. + uint8 legend_colour; + uint8 rating_colour; + uint8 weight; ///< Weight of a single unit of this cargo type in 1/16 ton (62.5 kg). + uint16 multiplier; ///< Capacity multiplier for vehicles. (8 fractional bits) + uint16 initial_payment; + uint8 transit_days[2]; + + bool is_freight; ///< Cargo type is considered to be freight (affects train freight multiplier). + TownEffect town_effect; ///< The effect that delivering this cargo type has on towns. Also affects destination of subsidies. + uint16 multipliertowngrowth; ///< Size of the effect. + uint8 callback_mask; ///< Bitmask of cargo callbacks that have to be called + + StringID name; ///< Name of this type of cargo. + StringID name_single; ///< Name of a single entity of this type of cargo. + StringID units_volume; ///< Name of a single unit of cargo of this type. + StringID quantifier; ///< Text for multiple units of cargo of this type. + StringID abbrev; ///< Two letter abbreviation for this cargo type. + + SpriteID sprite; ///< Icon to display this cargo type, may be \c 0xFFF (which means to resolve an action123 chain). + + uint16 classes; ///< Classes of this cargo type. @see CargoClass + const struct GRFFile *grffile; ///< NewGRF where #group belongs to. + const struct SpriteGroup *group; + + Money current_payment; + + /** + * Determines index of this cargospec + * @return index (in the CargoSpec::array array) + */ + inline CargoID Index() const + { + return this - CargoSpec::array; + } + + /** + * Tests for validity of this cargospec + * @return is this cargospec valid? + * @note assert(cs->IsValid()) can be triggered when GRF config is modified + */ + inline bool IsValid() const + { + return this->bitnum != INVALID_CARGO; + } + + /** + * Total number of cargospecs, both valid and invalid + * @return length of CargoSpec::array + */ + static inline size_t GetArraySize() + { + return lengthof(CargoSpec::array); + } + + /** + * Retrieve cargo details for the given cargo ID + * @param index ID of cargo + * @pre index is a valid cargo ID + */ + static inline CargoSpec *Get(size_t index) + { + assert(index < lengthof(CargoSpec::array)); + return &CargoSpec::array[index]; + } + + SpriteID GetCargoIcon() const; + +private: + static CargoSpec array[NUM_CARGO]; ///< Array holding all CargoSpecs + + friend void SetupCargoForClimate(LandscapeID l); +}; + +extern uint32 _cargo_mask; +extern uint32 _standard_cargo_mask; + +void SetupCargoForClimate(LandscapeID l); +CargoID GetCargoIDByLabel(CargoLabel cl); +CargoID GetCargoIDByBitnum(uint8 bitnum); + +void InitializeSortedCargoSpecs(); +extern const CargoSpec *_sorted_cargo_specs[NUM_CARGO]; +extern uint8 _sorted_cargo_specs_size; +extern uint8 _sorted_standard_cargo_specs_size; + +/** + * Does cargo \a c have cargo class \a cc? + * @param c Cargo type. + * @param cc Cargo class. + * @return The type fits in the class. + */ +static inline bool IsCargoInClass(CargoID c, CargoClass cc) +{ + return (CargoSpec::Get(c)->classes & cc) != 0; +} + +#define FOR_ALL_CARGOSPECS_FROM(var, start) for (size_t cargospec_index = start; var = NULL, cargospec_index < CargoSpec::GetArraySize(); cargospec_index++) \ + if ((var = CargoSpec::Get(cargospec_index))->IsValid()) +#define FOR_ALL_CARGOSPECS(var) FOR_ALL_CARGOSPECS_FROM(var, 0) + +#define FOR_EACH_SET_CARGO_ID(var, cargo_bits) FOR_EACH_SET_BIT_EX(CargoID, var, uint, cargo_bits) + +/** + * Loop header for iterating over cargoes, sorted by name. This includes phony cargoes like regearing cargoes. + * @param var Reference getting the cargospec. + * @see CargoSpec + */ +#define FOR_ALL_SORTED_CARGOSPECS(var) for (uint8 index = 0; index < _sorted_cargo_specs_size && (var = _sorted_cargo_specs[index], true) ; index++) + +/** + * Loop header for iterating over 'real' cargoes, sorted by name. Phony cargoes like regearing cargoes are skipped. + * @param var Reference getting the cargospec. + * @see CargoSpec + */ +#define FOR_ALL_SORTED_STANDARD_CARGOSPECS(var) for (uint8 index = 0; index < _sorted_standard_cargo_specs_size && (var = _sorted_cargo_specs[index], true); index++) + +#endif /* CARGOTYPE_H */ diff --git a/src/cheat.cpp b/src/cheat.cpp new file mode 100644 index 0000000..8b300c9 --- /dev/null +++ b/src/cheat.cpp @@ -0,0 +1,41 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file cheat.cpp Handling (loading/saving/initializing) of cheats. */ + +#include "stdafx.h" +#include "cheat_type.h" + +#include "safeguards.h" + +/** All the cheats. */ +Cheats _cheats; + +/** Reinitialise all the cheats. */ +void InitializeCheats() +{ + memset(&_cheats, 0, sizeof(Cheats)); +} + +/** + * Return true if any cheat has been used, false otherwise + * @return has a cheat been used? + */ +bool CheatHasBeenUsed() +{ + /* Cannot use lengthof because _cheats is of type Cheats, not Cheat */ + const Cheat *cht = (Cheat*)&_cheats; + const Cheat *cht_last = &cht[sizeof(_cheats) / sizeof(Cheat)]; + + for (; cht != cht_last; cht++) { + if (cht->been_used) return true; + } + + return false; +} diff --git a/src/cheat_func.h b/src/cheat_func.h new file mode 100644 index 0000000..e774abc --- /dev/null +++ b/src/cheat_func.h @@ -0,0 +1,23 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file cheat_func.h Functions related to cheating. */ + +#ifndef CHEAT_FUNC_H +#define CHEAT_FUNC_H + +#include "cheat_type.h" + +extern Cheats _cheats; + +void ShowCheatWindow(); + +bool CheatHasBeenUsed(); + +#endif /* CHEAT_FUNC_H */ diff --git a/src/cheat_gui.cpp b/src/cheat_gui.cpp new file mode 100644 index 0000000..fda2b24 --- /dev/null +++ b/src/cheat_gui.cpp @@ -0,0 +1,422 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file cheat_gui.cpp GUI related to cheating. */ + +#include "stdafx.h" +#include "command_func.h" +#include "cheat_type.h" +#include "company_base.h" +#include "company_func.h" +#include "date_func.h" +#include "saveload/saveload.h" +#include "textbuf_gui.h" +#include "window_gui.h" +#include "string_func.h" +#include "strings_func.h" +#include "window_func.h" +#include "rail_gui.h" +#include "settings_gui.h" +#include "company_gui.h" +#include "linkgraph/linkgraphschedule.h" +#include "map_func.h" +#include "tile_map.h" +#include "newgrf.h" +#include "error.h" + +#include "widgets/cheat_widget.h" + +#include "table/sprites.h" + +#include "safeguards.h" + + +/** + * The 'amount' to cheat with. + * This variable is semantically a constant value, but because the cheat + * code requires to be able to write to the variable it is not constified. + */ +static int32 _money_cheat_amount = 10000000; + +/** + * Handle cheating of money. + * Note that the amount of money of a company must be changed through a command + * rather than by setting a variable. Since the cheat data structure expects a + * variable, the amount of given/taken money is used for this purpose. + * @param p1 not used. + * @param p2 is -1 or +1 (down/up) + * @return Amount of money cheat. + */ +static int32 ClickMoneyCheat(int32 p1, int32 p2) +{ + DoCommandP(0, (uint32)(p2 * _money_cheat_amount), 0, CMD_MONEY_CHEAT); + return _money_cheat_amount; +} + +/** + * Handle changing of company. + * @param p1 company to set to + * @param p2 is -1 or +1 (down/up) + * @return The new company. + */ +static int32 ClickChangeCompanyCheat(int32 p1, int32 p2) +{ + while ((uint)p1 < Company::GetPoolSize()) { + if (Company::IsValidID((CompanyID)p1)) { + SetLocalCompany((CompanyID)p1); + return _local_company; + } + p1 += p2; + } + + return _local_company; +} + +/** + * Allow (or disallow) changing production of all industries. + * @param p1 new value + * @param p2 unused + * @return New value allowing change of industry production. + */ +static int32 ClickSetProdCheat(int32 p1, int32 p2) +{ + _cheats.setup_prod.value = (p1 != 0); + InvalidateWindowClassesData(WC_INDUSTRY_VIEW); + return _cheats.setup_prod.value; +} + +extern void EnginesMonthlyLoop(); + +/** + * Handle changing of the current year. + * @param p1 Unused. + * @param p2 +1 (increase) or -1 (decrease). + * @return New year. + */ +static int32 ClickChangeDateCheat(int32 p1, int32 p2) +{ + YearMonthDay ymd; + ConvertDateToYMD(_date, &ymd); + + p1 = Clamp(p1, MIN_YEAR, MAX_YEAR); + if (p1 == _cur_year) return _cur_year; + + Date new_date = ConvertYMDToDate(p1, ymd.month, ymd.day); + LinkGraphSchedule::instance.ShiftDates(new_date - _date); + SetDate(new_date, _date_fract); + EnginesMonthlyLoop(); + SetWindowDirty(WC_STATUS_BAR, 0); + InvalidateWindowClassesData(WC_BUILD_STATION, 0); + InvalidateWindowClassesData(WC_BUILD_OBJECT, 0); + ResetSignalVariant(); + return _cur_year; +} + +/** + * Allow (or disallow) a change of the maximum allowed heightlevel. + * @param p1 new value + * @param p2 unused + * @return New value (or unchanged old value) of the maximum + * allowed heightlevel value. + */ +static int32 ClickChangeMaxHlCheat(int32 p1, int32 p2) +{ + p1 = Clamp(p1, MIN_MAX_HEIGHTLEVEL, MAX_MAX_HEIGHTLEVEL); + + /* Check if at least one mountain on the map is higher than the new value. + * If yes, disallow the change. */ + for (TileIndex t = 0; t < MapSize(); t++) { + if ((int32)TileHeight(t) > p1) { + ShowErrorMessage(STR_CONFIG_SETTING_TOO_HIGH_MOUNTAIN, INVALID_STRING_ID, WL_ERROR); + /* Return old, unchanged value */ + return _settings_game.construction.max_heightlevel; + } + } + + /* Execute the change and reload GRF Data */ + _settings_game.construction.max_heightlevel = p1; + ReloadNewGRFData(); + + /* The smallmap uses an index from heightlevels to colours. Trigger rebuilding it. */ + InvalidateWindowClassesData(WC_SMALLMAP, 2); + + return _settings_game.construction.max_heightlevel; +} + +/** Available cheats. */ +enum CheatNumbers { + CHT_MONEY, ///< Change amount of money. + CHT_CHANGE_COMPANY, ///< Switch company. + CHT_EXTRA_DYNAMITE, ///< Dynamite anything. + CHT_CROSSINGTUNNELS, ///< Allow tunnels to cross each other. + CHT_NO_JETCRASH, ///< Disable jet-airplane crashes. + CHT_SETUP_PROD, ///< Allow manually editing of industry production. + CHT_EDIT_MAX_HL, ///< Edit maximum allowed heightlevel + CHT_CHANGE_DATE, ///< Do time traveling. + + CHT_NUM_CHEATS, ///< Number of cheats. +}; + +/** + * Signature of handler function when user clicks at a cheat. + * @param p1 The new value. + * @param p2 Change direction (+1, +1), \c 0 for boolean settings. + */ +typedef int32 CheckButtonClick(int32 p1, int32 p2); + +/** Information of a cheat. */ +struct CheatEntry { + VarType type; ///< type of selector + StringID str; ///< string with descriptive text + void *variable; ///< pointer to the variable + bool *been_used; ///< has this cheat been used before? + CheckButtonClick *proc;///< procedure +}; + +/** + * The available cheats. + * Order matches with the values of #CheatNumbers + */ +static const CheatEntry _cheats_ui[] = { + {SLE_INT32, STR_CHEAT_MONEY, &_money_cheat_amount, &_cheats.money.been_used, &ClickMoneyCheat }, + {SLE_UINT8, STR_CHEAT_CHANGE_COMPANY, &_local_company, &_cheats.switch_company.been_used, &ClickChangeCompanyCheat }, + {SLE_BOOL, STR_CHEAT_EXTRA_DYNAMITE, &_cheats.magic_bulldozer.value, &_cheats.magic_bulldozer.been_used, NULL }, + {SLE_BOOL, STR_CHEAT_CROSSINGTUNNELS, &_cheats.crossing_tunnels.value, &_cheats.crossing_tunnels.been_used, NULL }, + {SLE_BOOL, STR_CHEAT_NO_JETCRASH, &_cheats.no_jetcrash.value, &_cheats.no_jetcrash.been_used, NULL }, + {SLE_BOOL, STR_CHEAT_SETUP_PROD, &_cheats.setup_prod.value, &_cheats.setup_prod.been_used, &ClickSetProdCheat }, + {SLE_UINT8, STR_CHEAT_EDIT_MAX_HL, &_settings_game.construction.max_heightlevel, &_cheats.edit_max_hl.been_used, &ClickChangeMaxHlCheat }, + {SLE_INT32, STR_CHEAT_CHANGE_DATE, &_cur_year, &_cheats.change_date.been_used, &ClickChangeDateCheat }, +}; + +assert_compile(CHT_NUM_CHEATS == lengthof(_cheats_ui)); + +/** Widget definitions of the cheat GUI. */ +static const NWidgetPart _nested_cheat_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_CHEATS, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_STICKYBOX, COLOUR_GREY), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_C_PANEL), SetDataTip(0x0, STR_CHEATS_TOOLTIP), EndContainer(), +}; + +/** GUI for the cheats. */ +struct CheatWindow : Window { + int clicked; + int header_height; + int clicked_widget; + uint line_height; + int box_width; + + CheatWindow(WindowDesc *desc) : Window(desc) + { + this->box_width = GetSpriteSize(SPR_BOX_EMPTY).width; + this->InitNested(); + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + if (widget != WID_C_PANEL) return; + + int y = r.top + WD_FRAMERECT_TOP + this->header_height; + DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, r.top + WD_FRAMERECT_TOP, y, STR_CHEATS_WARNING, TC_FROMSTRING, SA_CENTER); + + bool rtl = _current_text_dir == TD_RTL; + uint box_left = rtl ? r.right - this->box_width - 5 : r.left + 5; + uint button_left = rtl ? r.right - this->box_width - 10 - SETTING_BUTTON_WIDTH : r.left + this->box_width + 10; + uint text_left = r.left + (rtl ? WD_FRAMERECT_LEFT : 20 + this->box_width + SETTING_BUTTON_WIDTH); + uint text_right = r.right - (rtl ? 20 + this->box_width + SETTING_BUTTON_WIDTH : WD_FRAMERECT_RIGHT); + + int text_y_offset = (this->line_height - FONT_HEIGHT_NORMAL) / 2; + int icon_y_offset = (this->line_height - SETTING_BUTTON_HEIGHT) / 2; + + for (int i = 0; i != lengthof(_cheats_ui); i++) { + const CheatEntry *ce = &_cheats_ui[i]; + + DrawSprite((*ce->been_used) ? SPR_BOX_CHECKED : SPR_BOX_EMPTY, PAL_NONE, box_left, y + icon_y_offset + 2); + + switch (ce->type) { + case SLE_BOOL: { + bool on = (*(bool*)ce->variable); + + DrawBoolButton(button_left, y + icon_y_offset, on, true); + SetDParam(0, on ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF); + break; + } + + default: { + int32 val = (int32)ReadValue(ce->variable, ce->type); + char buf[512]; + + /* Draw [<][>] boxes for settings of an integer-type */ + DrawArrowButtons(button_left, y + icon_y_offset, COLOUR_YELLOW, clicked - (i * 2), true, true); + + switch (ce->str) { + /* Display date for change date cheat */ + case STR_CHEAT_CHANGE_DATE: SetDParam(0, _date); break; + + /* Draw coloured flag for change company cheat */ + case STR_CHEAT_CHANGE_COMPANY: { + SetDParam(0, val + 1); + GetString(buf, STR_CHEAT_CHANGE_COMPANY, lastof(buf)); + uint offset = 10 + GetStringBoundingBox(buf).width; + DrawCompanyIcon(_local_company, rtl ? text_right - offset - 10 : text_left + offset, y + icon_y_offset + 2); + break; + } + + default: SetDParam(0, val); + } + break; + } + } + + DrawString(text_left, text_right, y + text_y_offset, ce->str); + + y += this->line_height; + } + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + if (widget != WID_C_PANEL) return; + + uint width = 0; + for (int i = 0; i != lengthof(_cheats_ui); i++) { + const CheatEntry *ce = &_cheats_ui[i]; + switch (ce->type) { + case SLE_BOOL: + SetDParam(0, STR_CONFIG_SETTING_ON); + width = max(width, GetStringBoundingBox(ce->str).width); + SetDParam(0, STR_CONFIG_SETTING_OFF); + width = max(width, GetStringBoundingBox(ce->str).width); + break; + + default: + switch (ce->str) { + /* Display date for change date cheat */ + case STR_CHEAT_CHANGE_DATE: + SetDParam(0, ConvertYMDToDate(MAX_YEAR, 11, 31)); + width = max(width, GetStringBoundingBox(ce->str).width); + break; + + /* Draw coloured flag for change company cheat */ + case STR_CHEAT_CHANGE_COMPANY: + SetDParamMaxValue(0, MAX_COMPANIES); + width = max(width, GetStringBoundingBox(ce->str).width + 10 + 10); + break; + + default: + SetDParam(0, INT64_MAX); + width = max(width, GetStringBoundingBox(ce->str).width); + break; + } + break; + } + } + + this->line_height = max(GetSpriteSize(SPR_BOX_CHECKED).height, GetSpriteSize(SPR_BOX_EMPTY).height); + this->line_height = max(this->line_height, SETTING_BUTTON_HEIGHT); + this->line_height = max(this->line_height, FONT_HEIGHT_NORMAL) + WD_PAR_VSEP_NORMAL; + + size->width = width + 20 + this->box_width + SETTING_BUTTON_WIDTH /* stuff on the left */ + 10 /* extra spacing on right */; + this->header_height = GetStringHeight(STR_CHEATS_WARNING, size->width - WD_FRAMERECT_LEFT - WD_FRAMERECT_RIGHT) + WD_PAR_VSEP_WIDE; + size->height = this->header_height + WD_FRAMERECT_TOP + WD_PAR_VSEP_NORMAL + WD_FRAMERECT_BOTTOM + this->line_height * lengthof(_cheats_ui); + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + const NWidgetBase *wid = this->GetWidget(WID_C_PANEL); + uint btn = (pt.y - wid->pos_y - WD_FRAMERECT_TOP - this->header_height) / this->line_height; + int x = pt.x - wid->pos_x; + bool rtl = _current_text_dir == TD_RTL; + if (rtl) x = wid->current_x - x; + + if (btn >= lengthof(_cheats_ui)) return; + + const CheatEntry *ce = &_cheats_ui[btn]; + int value = (int32)ReadValue(ce->variable, ce->type); + int oldvalue = value; + + if (btn == CHT_CHANGE_DATE && x >= 20 + this->box_width + SETTING_BUTTON_WIDTH) { + /* Click at the date text directly. */ + clicked_widget = CHT_CHANGE_DATE; + SetDParam(0, value); + ShowQueryString(STR_JUST_INT, STR_CHEAT_CHANGE_DATE_QUERY_CAPT, 8, this, CS_NUMERAL, QSF_ACCEPT_UNCHANGED); + return; + } else if (btn == CHT_EDIT_MAX_HL && x >= 20 + this->box_width + SETTING_BUTTON_WIDTH) { + clicked_widget = CHT_EDIT_MAX_HL; + SetDParam(0, value); + ShowQueryString(STR_JUST_INT, STR_CHEAT_EDIT_MAX_HL_QUERY_CAPT, 8, this, CS_NUMERAL, QSF_ACCEPT_UNCHANGED); + return; + } + + /* Not clicking a button? */ + if (!IsInsideMM(x, 10 + this->box_width, 10 + this->box_width + SETTING_BUTTON_WIDTH)) return; + + *ce->been_used = true; + + switch (ce->type) { + case SLE_BOOL: + value ^= 1; + if (ce->proc != NULL) ce->proc(value, 0); + break; + + default: + /* Take whatever the function returns */ + value = ce->proc(value + ((x >= 20 + SETTING_BUTTON_WIDTH / 2) ? 1 : -1), (x >= 10 + this->box_width + SETTING_BUTTON_WIDTH / 2) ? 1 : -1); + + /* The first cheat (money), doesn't return a different value. */ + if (value != oldvalue || btn == CHT_MONEY) this->clicked = btn * 2 + 1 + ((x >= 10 + this->box_width + SETTING_BUTTON_WIDTH / 2) != rtl ? 1 : 0); + break; + } + + if (value != oldvalue) WriteValue(ce->variable, ce->type, (int64)value); + + this->SetTimeout(); + + this->SetDirty(); + } + + virtual void OnTimeout() + { + this->clicked = 0; + this->SetDirty(); + } + + virtual void OnQueryTextFinished(char *str) + { + /* Was 'cancel' pressed or nothing entered? */ + if (str == NULL || StrEmpty(str)) return; + + const CheatEntry *ce = &_cheats_ui[clicked_widget]; + int oldvalue = (int32)ReadValue(ce->variable, ce->type); + int value = atoi(str); + *ce->been_used = true; + value = ce->proc(value, value - oldvalue); + + if (value != oldvalue) WriteValue(ce->variable, ce->type, (int64)value); + this->SetDirty(); + } +}; + +/** Window description of the cheats GUI. */ +static WindowDesc _cheats_desc( + WDP_AUTO, "cheats", 0, 0, + WC_CHEATS, WC_NONE, + 0, + _nested_cheat_widgets, lengthof(_nested_cheat_widgets) +); + +/** Open cheat window. */ +void ShowCheatWindow() +{ + DeleteWindowById(WC_CHEATS, 0); + new CheatWindow(&_cheats_desc); +} diff --git a/src/cheat_type.h b/src/cheat_type.h new file mode 100644 index 0000000..a75acf3 --- /dev/null +++ b/src/cheat_type.h @@ -0,0 +1,44 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file cheat_type.h Types related to cheating. */ + +#ifndef CHEAT_TYPE_H +#define CHEAT_TYPE_H + +/** + * Info about each of the cheats. + */ +struct Cheat { + bool been_used; ///< has this cheat been used before? + bool value; ///< tells if the bool cheat is active or not +}; + +/** + * WARNING! Do _not_ remove entries in Cheats struct or change the order + * of the existing ones! Would break downward compatibility. + * Only add new entries at the end of the struct! + */ +struct Cheats { + Cheat magic_bulldozer; ///< dynamite industries, objects + Cheat switch_company; ///< change to another company + Cheat money; ///< get rich or poor + Cheat crossing_tunnels; ///< allow tunnels that cross each other + Cheat dummy1; ///< empty cheat (build while in pause mode) + Cheat no_jetcrash; ///< no jet will crash on small airports anymore + Cheat dummy2; ///< empty cheat (change the climate of the map) + Cheat change_date; ///< changes date ingame + Cheat setup_prod; ///< setup raw-material production in game + Cheat dummy3; ///< empty cheat (enable running el-engines on normal rail) + Cheat edit_max_hl; ///< edit the maximum heightlevel; this is a cheat because of the fact that it needs to reset NewGRF game state and doing so as a simple configuration breaks the expectation of many +}; + +extern Cheats _cheats; + +#endif /* CHEAT_TYPE_H */ diff --git a/src/clear_cmd.cpp b/src/clear_cmd.cpp new file mode 100644 index 0000000..2e9589a --- /dev/null +++ b/src/clear_cmd.cpp @@ -0,0 +1,402 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file clear_cmd.cpp Commands related to clear tiles. */ + +#include "stdafx.h" +#include "clear_map.h" +#include "command_func.h" +#include "landscape.h" +#include "genworld.h" +#include "viewport_func.h" +#include "water.h" +#include "core/random_func.hpp" +#include "newgrf_generic.h" + +#include "table/strings.h" +#include "table/sprites.h" +#include "table/clear_land.h" + +#include "safeguards.h" + +static CommandCost ClearTile_Clear(TileIndex tile, DoCommandFlag flags) +{ + static const Price clear_price_table[] = { + PR_CLEAR_GRASS, + PR_CLEAR_ROUGH, + PR_CLEAR_ROCKS, + PR_CLEAR_FIELDS, + PR_CLEAR_ROUGH, + PR_CLEAR_ROUGH, + }; + CommandCost price(EXPENSES_CONSTRUCTION); + + if (!IsClearGround(tile, CLEAR_GRASS) || GetClearDensity(tile) != 0) { + price.AddCost(_price[clear_price_table[GetClearGround(tile)]]); + } + + if (flags & DC_EXEC) DoClearSquare(tile); + + return price; +} + +void DrawClearLandTile(const TileInfo *ti, byte set) +{ + DrawGroundSprite(SPR_FLAT_BARE_LAND + SlopeToSpriteOffset(ti->tileh) + set * 19, PAL_NONE); +} + +void DrawHillyLandTile(const TileInfo *ti) +{ + if (ti->tileh != SLOPE_FLAT) { + DrawGroundSprite(SPR_FLAT_ROUGH_LAND + SlopeToSpriteOffset(ti->tileh), PAL_NONE); + } else { + DrawGroundSprite(_landscape_clear_sprites_rough[GB(ti->x ^ ti->y, 4, 3)], PAL_NONE); + } +} + +static void DrawClearLandFence(const TileInfo *ti) +{ + /* combine fences into one sprite object */ + StartSpriteCombine(); + + int maxz = GetSlopeMaxPixelZ(ti->tileh); + + uint fence_nw = GetFence(ti->tile, DIAGDIR_NW); + if (fence_nw != 0) { + int z = GetSlopePixelZInCorner(ti->tileh, CORNER_W); + SpriteID sprite = _clear_land_fence_sprites[fence_nw - 1] + _fence_mod_by_tileh_nw[ti->tileh]; + AddSortableSpriteToDraw(sprite, PAL_NONE, ti->x, ti->y - 15, 16, 31, maxz - z + 4, ti->z + z, false, 0, 15, -z); + } + + uint fence_ne = GetFence(ti->tile, DIAGDIR_NE); + if (fence_ne != 0) { + int z = GetSlopePixelZInCorner(ti->tileh, CORNER_E); + SpriteID sprite = _clear_land_fence_sprites[fence_ne - 1] + _fence_mod_by_tileh_ne[ti->tileh]; + AddSortableSpriteToDraw(sprite, PAL_NONE, ti->x - 15, ti->y, 31, 16, maxz - z + 4, ti->z + z, false, 15, 0, -z); + } + + uint fence_sw = GetFence(ti->tile, DIAGDIR_SW); + uint fence_se = GetFence(ti->tile, DIAGDIR_SE); + + if (fence_sw != 0 || fence_se != 0) { + int z = GetSlopePixelZInCorner(ti->tileh, CORNER_S); + + if (fence_sw != 0) { + SpriteID sprite = _clear_land_fence_sprites[fence_sw - 1] + _fence_mod_by_tileh_sw[ti->tileh]; + AddSortableSpriteToDraw(sprite, PAL_NONE, ti->x, ti->y, 16, 16, maxz - z + 4, ti->z + z, false, 0, 0, -z); + } + + if (fence_se != 0) { + SpriteID sprite = _clear_land_fence_sprites[fence_se - 1] + _fence_mod_by_tileh_se[ti->tileh]; + AddSortableSpriteToDraw(sprite, PAL_NONE, ti->x, ti->y, 16, 16, maxz - z + 4, ti->z + z, false, 0, 0, -z); + } + } + EndSpriteCombine(); +} + +static void DrawTile_Clear(TileInfo *ti) +{ + switch (GetClearGround(ti->tile)) { + case CLEAR_GRASS: + DrawClearLandTile(ti, GetClearDensity(ti->tile)); + break; + + case CLEAR_ROUGH: + DrawHillyLandTile(ti); + break; + + case CLEAR_ROCKS: + DrawGroundSprite((HasGrfMiscBit(GMB_SECOND_ROCKY_TILE_SET) && (TileHash(ti->x, ti->y) & 1) ? SPR_FLAT_ROCKY_LAND_2 : SPR_FLAT_ROCKY_LAND_1) + SlopeToSpriteOffset(ti->tileh), PAL_NONE); + break; + + case CLEAR_FIELDS: + DrawGroundSprite(_clear_land_sprites_farmland[GetFieldType(ti->tile)] + SlopeToSpriteOffset(ti->tileh), PAL_NONE); + DrawClearLandFence(ti); + break; + + case CLEAR_SNOW: + case CLEAR_DESERT: + DrawGroundSprite(_clear_land_sprites_snow_desert[GetClearDensity(ti->tile)] + SlopeToSpriteOffset(ti->tileh), PAL_NONE); + break; + } + + DrawBridgeMiddle(ti); +} + +static int GetSlopePixelZ_Clear(TileIndex tile, uint x, uint y) +{ + int z; + Slope tileh = GetTilePixelSlope(tile, &z); + + return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh); +} + +static Foundation GetFoundation_Clear(TileIndex tile, Slope tileh) +{ + return FOUNDATION_NONE; +} + +static void UpdateFences(TileIndex tile) +{ + assert(IsTileType(tile, MP_CLEAR) && IsClearGround(tile, CLEAR_FIELDS)); + bool dirty = false; + + bool neighbour = (IsTileType(TILE_ADDXY(tile, 1, 0), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 1, 0), CLEAR_FIELDS)); + if (!neighbour && GetFence(tile, DIAGDIR_SW) == 0) { + SetFence(tile, DIAGDIR_SW, 3); + dirty = true; + } + + neighbour = (IsTileType(TILE_ADDXY(tile, 0, 1), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 0, 1), CLEAR_FIELDS)); + if (!neighbour && GetFence(tile, DIAGDIR_SE) == 0) { + SetFence(tile, DIAGDIR_SE, 3); + dirty = true; + } + + neighbour = (IsTileType(TILE_ADDXY(tile, -1, 0), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, -1, 0), CLEAR_FIELDS)); + if (!neighbour && GetFence(tile, DIAGDIR_NE) == 0) { + SetFence(tile, DIAGDIR_NE, 3); + dirty = true; + } + + neighbour = (IsTileType(TILE_ADDXY(tile, 0, -1), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 0, -1), CLEAR_FIELDS)); + if (!neighbour && GetFence(tile, DIAGDIR_NW) == 0) { + SetFence(tile, DIAGDIR_NW, 3); + dirty = true; + } + + if (dirty) MarkTileDirtyByTile(tile); +} + + +/** Convert to or from snowy tiles. */ +static void TileLoopClearAlps(TileIndex tile) +{ + int k = GetTileZ(tile) - GetSnowLine() + 1; + + if (k < 0) { + /* Below the snow line, do nothing if no snow. */ + if (!IsSnowTile(tile)) return; + } else { + /* At or above the snow line, make snow tile if needed. */ + if (!IsSnowTile(tile)) { + MakeSnow(tile); + MarkTileDirtyByTile(tile); + return; + } + } + /* Update snow density. */ + uint current_density = GetClearDensity(tile); + uint req_density = (k < 0) ? 0u : min((uint)k, 3); + + if (current_density < req_density) { + AddClearDensity(tile, 1); + } else if (current_density > req_density) { + AddClearDensity(tile, -1); + } else { + /* Density at the required level. */ + if (k >= 0) return; + ClearSnow(tile); + } + MarkTileDirtyByTile(tile); +} + +/** + * Tests if at least one surrounding tile is desert + * @param tile tile to check + * @return does this tile have at least one desert tile around? + */ +static inline bool NeighbourIsDesert(TileIndex tile) +{ + return GetTropicZone(tile + TileDiffXY( 1, 0)) == TROPICZONE_DESERT || + GetTropicZone(tile + TileDiffXY( -1, 0)) == TROPICZONE_DESERT || + GetTropicZone(tile + TileDiffXY( 0, 1)) == TROPICZONE_DESERT || + GetTropicZone(tile + TileDiffXY( 0, -1)) == TROPICZONE_DESERT; +} + +static void TileLoopClearDesert(TileIndex tile) +{ + /* Current desert level - 0 if it is not desert */ + uint current = 0; + if (IsClearGround(tile, CLEAR_DESERT)) current = GetClearDensity(tile); + + /* Expected desert level - 0 if it shouldn't be desert */ + uint expected = 0; + if (GetTropicZone(tile) == TROPICZONE_DESERT) { + expected = 3; + } else if (NeighbourIsDesert(tile)) { + expected = 1; + } + + if (current == expected) return; + + if (expected == 0) { + SetClearGroundDensity(tile, CLEAR_GRASS, 3); + } else { + /* Transition from clear to desert is not smooth (after clearing desert tile) */ + SetClearGroundDensity(tile, CLEAR_DESERT, expected); + } + + MarkTileDirtyByTile(tile); +} + +static void TileLoop_Clear(TileIndex tile) +{ + /* If the tile is at any edge flood it to prevent maps without water. */ + if (_settings_game.construction.freeform_edges && DistanceFromEdge(tile) == 1) { + int z; + if (IsTileFlat(tile, &z) && z == 0) { + DoFloodTile(tile); + MarkTileDirtyByTile(tile); + return; + } + } + AmbientSoundEffect(tile); + + switch (_settings_game.game_creation.landscape) { + case LT_TROPIC: TileLoopClearDesert(tile); break; + case LT_ARCTIC: TileLoopClearAlps(tile); break; + } + + switch (GetClearGround(tile)) { + case CLEAR_GRASS: + if (GetClearDensity(tile) == 3) return; + + if (_game_mode != GM_EDITOR) { + if (GetClearCounter(tile) < 7) { + AddClearCounter(tile, 1); + return; + } else { + SetClearCounter(tile, 0); + AddClearDensity(tile, 1); + } + } else { + SetClearGroundDensity(tile, GB(Random(), 0, 8) > 21 ? CLEAR_GRASS : CLEAR_ROUGH, 3); + } + break; + + case CLEAR_FIELDS: + UpdateFences(tile); + + if (_game_mode == GM_EDITOR) return; + + if (GetClearCounter(tile) < 7) { + AddClearCounter(tile, 1); + return; + } else { + SetClearCounter(tile, 0); + } + + if (GetIndustryIndexOfField(tile) == INVALID_INDUSTRY && GetFieldType(tile) >= 7) { + /* This farmfield is no longer farmfield, so make it grass again */ + MakeClear(tile, CLEAR_GRASS, 2); + } else { + uint field_type = GetFieldType(tile); + field_type = (field_type < 8) ? field_type + 1 : 0; + SetFieldType(tile, field_type); + } + break; + + default: + return; + } + + MarkTileDirtyByTile(tile); +} + +void GenerateClearTile() +{ + uint i, gi; + TileIndex tile; + + /* add rough tiles */ + i = ScaleByMapSize(GB(Random(), 0, 10) + 0x400); + gi = ScaleByMapSize(GB(Random(), 0, 7) + 0x80); + + SetGeneratingWorldProgress(GWP_ROUGH_ROCKY, gi + i); + do { + IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY); + tile = RandomTile(); + if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) SetClearGroundDensity(tile, CLEAR_ROUGH, 3); + } while (--i); + + /* add rocky tiles */ + i = gi; + do { + uint32 r = Random(); + tile = RandomTileSeed(r); + + IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY); + if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) { + uint j = GB(r, 16, 4) + 5; + for (;;) { + TileIndex tile_new; + + SetClearGroundDensity(tile, CLEAR_ROCKS, 3); + do { + if (--j == 0) goto get_out; + tile_new = tile + TileOffsByDiagDir((DiagDirection)GB(Random(), 0, 2)); + } while (!IsTileType(tile_new, MP_CLEAR) || IsClearGround(tile_new, CLEAR_DESERT)); + tile = tile_new; + } +get_out:; + } + } while (--i); +} + +static TrackStatus GetTileTrackStatus_Clear(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side) +{ + return 0; +} + +static const StringID _clear_land_str[] = { + STR_LAI_CLEAR_DESCRIPTION_GRASS, + STR_LAI_CLEAR_DESCRIPTION_ROUGH_LAND, + STR_LAI_CLEAR_DESCRIPTION_ROCKS, + STR_LAI_CLEAR_DESCRIPTION_FIELDS, + STR_LAI_CLEAR_DESCRIPTION_SNOW_COVERED_LAND, + STR_LAI_CLEAR_DESCRIPTION_DESERT +}; + +static void GetTileDesc_Clear(TileIndex tile, TileDesc *td) +{ + if (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) == 0) { + td->str = STR_LAI_CLEAR_DESCRIPTION_BARE_LAND; + } else { + td->str = _clear_land_str[GetClearGround(tile)]; + } + td->owner[0] = GetTileOwner(tile); +} + +static void ChangeTileOwner_Clear(TileIndex tile, Owner old_owner, Owner new_owner) +{ + return; +} + +static CommandCost TerraformTile_Clear(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new) +{ + return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); +} + +extern const TileTypeProcs _tile_type_clear_procs = { + DrawTile_Clear, ///< draw_tile_proc + GetSlopePixelZ_Clear, ///< get_slope_z_proc + ClearTile_Clear, ///< clear_tile_proc + NULL, ///< add_accepted_cargo_proc + GetTileDesc_Clear, ///< get_tile_desc_proc + GetTileTrackStatus_Clear, ///< get_tile_track_status_proc + NULL, ///< click_tile_proc + NULL, ///< animate_tile_proc + TileLoop_Clear, ///< tile_loop_proc + ChangeTileOwner_Clear, ///< change_tile_owner_proc + NULL, ///< add_produced_cargo_proc + NULL, ///< vehicle_enter_tile_proc + GetFoundation_Clear, ///< get_foundation_proc + TerraformTile_Clear, ///< terraform_tile_proc +}; diff --git a/src/clear_func.h b/src/clear_func.h new file mode 100644 index 0000000..b128288 --- /dev/null +++ b/src/clear_func.h @@ -0,0 +1,20 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file clear_func.h Functions related to clear (MP_CLEAR) land. */ + +#ifndef CLEAR_FUNC_H +#define CLEAR_FUNC_H + +#include "tile_cmd.h" + +void DrawHillyLandTile(const TileInfo *ti); +void DrawClearLandTile(const TileInfo *ti, byte set); + +#endif /* CLEAR_FUNC_H */ diff --git a/src/clear_map.h b/src/clear_map.h new file mode 100644 index 0000000..76b1e82 --- /dev/null +++ b/src/clear_map.h @@ -0,0 +1,323 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file clear_map.h Map accessors for 'clear' tiles */ + +#ifndef CLEAR_MAP_H +#define CLEAR_MAP_H + +#include "bridge_map.h" +#include "industry_type.h" + +/** + * Ground types. Valid densities in comments after the enum. + */ +enum ClearGround { + CLEAR_GRASS = 0, ///< 0-3 + CLEAR_ROUGH = 1, ///< 3 + CLEAR_ROCKS = 2, ///< 3 + CLEAR_FIELDS = 3, ///< 3 + CLEAR_SNOW = 4, ///< 0-3 + CLEAR_DESERT = 5, ///< 1,3 +}; + + +/** + * Test if a tile is covered with snow. + * @param t the tile to check + * @pre IsTileType(t, MP_CLEAR) + * @return whether the tile is covered with snow. + */ +static inline bool IsSnowTile(TileIndex t) +{ + assert(IsTileType(t, MP_CLEAR)); + return HasBit(_m[t].m3, 4); +} + +/** + * Get the type of clear tile but never return CLEAR_SNOW. + * @param t the tile to get the clear ground type of + * @pre IsTileType(t, MP_CLEAR) + * @return the ground type + */ +static inline ClearGround GetRawClearGround(TileIndex t) +{ + assert(IsTileType(t, MP_CLEAR)); + return (ClearGround)GB(_m[t].m5, 2, 3); +} + +/** + * Get the type of clear tile. + * @param t the tile to get the clear ground type of + * @pre IsTileType(t, MP_CLEAR) + * @return the ground type + */ +static inline ClearGround GetClearGround(TileIndex t) +{ + if (IsSnowTile(t)) return CLEAR_SNOW; + return GetRawClearGround(t); +} + +/** + * Set the type of clear tile. + * @param t the tile to set the clear ground type of + * @param ct the ground type + * @pre IsTileType(t, MP_CLEAR) + */ +static inline bool IsClearGround(TileIndex t, ClearGround ct) +{ + return GetClearGround(t) == ct; +} + + +/** + * Get the density of a non-field clear tile. + * @param t the tile to get the density of + * @pre IsTileType(t, MP_CLEAR) + * @return the density + */ +static inline uint GetClearDensity(TileIndex t) +{ + assert(IsTileType(t, MP_CLEAR)); + return GB(_m[t].m5, 0, 2); +} + +/** + * Increment the density of a non-field clear tile. + * @param t the tile to increment the density of + * @param d the amount to increment the density with + * @pre IsTileType(t, MP_CLEAR) + */ +static inline void AddClearDensity(TileIndex t, int d) +{ + assert(IsTileType(t, MP_CLEAR)); // XXX incomplete + _m[t].m5 += d; +} + +/** + * Set the density of a non-field clear tile. + * @param t the tile to set the density of + * @param d the new density + * @pre IsTileType(t, MP_CLEAR) + */ +static inline void SetClearDensity(TileIndex t, uint d) +{ + assert(IsTileType(t, MP_CLEAR)); + SB(_m[t].m5, 0, 2, d); +} + + +/** + * Get the counter used to advance to the next clear density/field type. + * @param t the tile to get the counter of + * @pre IsTileType(t, MP_CLEAR) + * @return the value of the counter + */ +static inline uint GetClearCounter(TileIndex t) +{ + assert(IsTileType(t, MP_CLEAR)); + return GB(_m[t].m5, 5, 3); +} + +/** + * Increments the counter used to advance to the next clear density/field type. + * @param t the tile to increment the counter of + * @param c the amount to increment the counter with + * @pre IsTileType(t, MP_CLEAR) + */ +static inline void AddClearCounter(TileIndex t, int c) +{ + assert(IsTileType(t, MP_CLEAR)); // XXX incomplete + _m[t].m5 += c << 5; +} + +/** + * Sets the counter used to advance to the next clear density/field type. + * @param t the tile to set the counter of + * @param c the amount to set the counter to + * @pre IsTileType(t, MP_CLEAR) + */ +static inline void SetClearCounter(TileIndex t, uint c) +{ + assert(IsTileType(t, MP_CLEAR)); // XXX incomplete + SB(_m[t].m5, 5, 3, c); +} + + +/** + * Sets ground type and density in one go, also sets the counter to 0 + * @param t the tile to set the ground type and density for + * @param type the new ground type of the tile + * @param density the density of the ground tile + * @pre IsTileType(t, MP_CLEAR) + */ +static inline void SetClearGroundDensity(TileIndex t, ClearGround type, uint density) +{ + assert(IsTileType(t, MP_CLEAR)); // XXX incomplete + _m[t].m5 = 0 << 5 | type << 2 | density; +} + + +/** + * Get the field type (production stage) of the field + * @param t the field to get the type of + * @pre GetClearGround(t) == CLEAR_FIELDS + * @return the field type + */ +static inline uint GetFieldType(TileIndex t) +{ + assert(GetClearGround(t) == CLEAR_FIELDS); + return GB(_m[t].m3, 0, 4); +} + +/** + * Set the field type (production stage) of the field + * @param t the field to get the type of + * @param f the field type + * @pre GetClearGround(t) == CLEAR_FIELDS + */ +static inline void SetFieldType(TileIndex t, uint f) +{ + assert(GetClearGround(t) == CLEAR_FIELDS); // XXX incomplete + SB(_m[t].m3, 0, 4, f); +} + +/** + * Get the industry (farm) that made the field + * @param t the field to get creating industry of + * @pre GetClearGround(t) == CLEAR_FIELDS + * @return the industry that made the field + */ +static inline IndustryID GetIndustryIndexOfField(TileIndex t) +{ + assert(GetClearGround(t) == CLEAR_FIELDS); + return(IndustryID) _m[t].m2; +} + +/** + * Set the industry (farm) that made the field + * @param t the field to get creating industry of + * @param i the industry that made the field + * @pre GetClearGround(t) == CLEAR_FIELDS + */ +static inline void SetIndustryIndexOfField(TileIndex t, IndustryID i) +{ + assert(GetClearGround(t) == CLEAR_FIELDS); + _m[t].m2 = i; +} + + +/** + * Is there a fence at the given border? + * @param t the tile to check for fences + * @param side the border to check + * @pre IsClearGround(t, CLEAR_FIELDS) + * @return 0 if there is no fence, otherwise the fence type + */ +static inline uint GetFence(TileIndex t, DiagDirection side) +{ + assert(IsClearGround(t, CLEAR_FIELDS)); + switch (side) { + default: NOT_REACHED(); + case DIAGDIR_SE: return GB(_m[t].m4, 2, 3); + case DIAGDIR_SW: return GB(_m[t].m4, 5, 3); + case DIAGDIR_NE: return GB(_m[t].m3, 5, 3); + case DIAGDIR_NW: return GB(_me[t].m6, 2, 3); + } +} + +/** + * Sets the type of fence (and whether there is one) for the given border. + * @param t the tile to check for fences + * @param side the border to check + * @param h 0 if there is no fence, otherwise the fence type + * @pre IsClearGround(t, CLEAR_FIELDS) + */ +static inline void SetFence(TileIndex t, DiagDirection side, uint h) +{ + assert(IsClearGround(t, CLEAR_FIELDS)); + switch (side) { + default: NOT_REACHED(); + case DIAGDIR_SE: SB(_m[t].m4, 2, 3, h); break; + case DIAGDIR_SW: SB(_m[t].m4, 5, 3, h); break; + case DIAGDIR_NE: SB(_m[t].m3, 5, 3, h); break; + case DIAGDIR_NW: SB(_me[t].m6, 2, 3, h); break; + } +} + + +/** + * Make a clear tile. + * @param t the tile to make a clear tile + * @param g the type of ground + * @param density the density of the grass/snow/desert etc + */ +static inline void MakeClear(TileIndex t, ClearGround g, uint density) +{ + SetTileType(t, MP_CLEAR); + _m[t].m1 = 0; + SetTileOwner(t, OWNER_NONE); + _m[t].m2 = 0; + _m[t].m3 = 0; + _m[t].m4 = 0 << 5 | 0 << 2; + SetClearGroundDensity(t, g, density); // Sets m5 + _me[t].m6 = 0; + _me[t].m7 = 0; +} + + +/** + * Make a (farm) field tile. + * @param t the tile to make a farm field + * @param field_type the 'growth' level of the field + * @param industry the industry this tile belongs to + */ +static inline void MakeField(TileIndex t, uint field_type, IndustryID industry) +{ + SetTileType(t, MP_CLEAR); + _m[t].m1 = 0; + SetTileOwner(t, OWNER_NONE); + _m[t].m2 = industry; + _m[t].m3 = field_type; + _m[t].m4 = 0 << 5 | 0 << 2; + SetClearGroundDensity(t, CLEAR_FIELDS, 3); + SB(_me[t].m6, 2, 4, 0); + _me[t].m7 = 0; +} + +/** + * Make a snow tile. + * @param t the tile to make snowy + * @param density The density of snowiness. + * @pre GetClearGround(t) != CLEAR_SNOW + */ +static inline void MakeSnow(TileIndex t, uint density = 0) +{ + assert(GetClearGround(t) != CLEAR_SNOW); + SetBit(_m[t].m3, 4); + if (GetRawClearGround(t) == CLEAR_FIELDS) { + SetClearGroundDensity(t, CLEAR_GRASS, density); + } else { + SetClearDensity(t, density); + } +} + +/** + * Clear the snow from a tile and return it to its previous type. + * @param t the tile to clear of snow + * @pre GetClearGround(t) == CLEAR_SNOW + */ +static inline void ClearSnow(TileIndex t) +{ + assert(GetClearGround(t) == CLEAR_SNOW); + ClrBit(_m[t].m3, 4); + SetClearDensity(t, 3); +} + +#endif /* CLEAR_MAP_H */ diff --git a/src/cmd_helper.h b/src/cmd_helper.h new file mode 100644 index 0000000..569708d --- /dev/null +++ b/src/cmd_helper.h @@ -0,0 +1,36 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file cmd_helper.h Helper functions to extract data from command parameters. */ + +#ifndef CMD_HELPER_H +#define CMD_HELPER_H + +#include "core/enum_type.hpp" +#include "core/bitmath_func.hpp" + +/** + * Extracts a given type from a value. + * @tparam T The type of data we're looking for. + * @tparam S The offset in the data. + * @tparam N The amount of bits to read. + * @tparam U The type of data passed to us. + * @param v The data to extract the value from. + */ +template static inline T Extract(U v) +{ + /* Check if there are enough bits in v */ + assert_tcompile(N == EnumPropsT::num_bits); + assert_tcompile(S + N <= sizeof(U) * 8); + assert_tcompile(EnumPropsT::end <= (1 << N)); + U masked = GB(v, S, N); + return IsInsideMM(masked, EnumPropsT::begin, EnumPropsT::end) ? (T)masked : EnumPropsT::invalid; +} + +#endif /* CMD_HELPER_H */ diff --git a/src/command.cpp b/src/command.cpp new file mode 100644 index 0000000..03ddde5 --- /dev/null +++ b/src/command.cpp @@ -0,0 +1,819 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file command.cpp Handling of commands. */ + +#include "stdafx.h" +#include "landscape.h" +#include "error.h" +#include "gui.h" +#include "command_func.h" +#include "network/network_type.h" +#include "network/network.h" +#include "genworld.h" +#include "strings_func.h" +#include "texteff.hpp" +#include "town.h" +#include "date_func.h" +#include "company_func.h" +#include "company_base.h" +#include "signal_func.h" +#include "core/backup_type.hpp" +#include "window_func.h" +#include "watch_gui.h" +#include "object_base.h" + +#include "table/strings.h" + +#include "safeguards.h" + +CommandProc CmdBuildRailroadTrack; +CommandProc CmdRemoveRailroadTrack; +CommandProc CmdBuildSingleRail; +CommandProc CmdRemoveSingleRail; + +CommandProc CmdLandscapeClear; + +CommandProc CmdBuildBridge; + +CommandProc CmdBuildRailStation; +CommandProc CmdRemoveFromRailStation; +CommandProc CmdConvertRail; + +CommandProc CmdBuildSingleSignal; +CommandProc CmdRemoveSingleSignal; + +CommandProc CmdTerraformLand; + +CommandProc CmdBuildObject; +CommandProc CmdSellLandArea; + +CommandProc CmdBuildTunnel; + +CommandProc CmdBuildTrainDepot; +CommandProc CmdBuildRailWaypoint; +CommandProc CmdRenameWaypoint; +CommandProc CmdRemoveFromRailWaypoint; + +CommandProc CmdBuildRoadStop; +CommandProc CmdRemoveRoadStop; + +CommandProc CmdBuildLongRoad; +CommandProc CmdRemoveLongRoad; +CommandProc CmdBuildRoad; + +CommandProc CmdBuildRoadDepot; + +CommandProc CmdBuildAirport; + +CommandProc CmdBuildDock; + +CommandProc CmdBuildShipDepot; + +CommandProc CmdBuildBuoy; + +CommandProc CmdPlantTree; + +CommandProc CmdMoveRailVehicle; + +CommandProc CmdBuildVehicle; +CommandProc CmdSellVehicle; +CommandProc CmdRefitVehicle; +CommandProc CmdSendVehicleToDepot; +CommandProc CmdSetVehicleVisibility; + +CommandProc CmdForceTrainProceed; +CommandProc CmdReverseTrainDirection; + +CommandProc CmdClearOrderBackup; +CommandProc CmdModifyOrder; +CommandProc CmdSkipToOrder; +CommandProc CmdDeleteOrder; +CommandProc CmdInsertOrder; +CommandProc CmdChangeServiceInt; + +CommandProc CmdBuildIndustry; + +CommandProc CmdSetCompanyManagerFace; +CommandProc CmdSetCompanyColour; + +CommandProc CmdIncreaseLoan; +CommandProc CmdDecreaseLoan; + +CommandProc CmdWantEnginePreview; + +CommandProc CmdRenameVehicle; +CommandProc CmdRenameEngine; + +CommandProc CmdRenameCompany; +CommandProc CmdRenamePresident; + +CommandProc CmdRenameStation; +CommandProc CmdRenameDepot; + +CommandProc CmdPlaceSign; +CommandProc CmdRenameSign; + +CommandProc CmdTurnRoadVeh; + +CommandProc CmdPause; + +CommandProc CmdBuyShareInCompany; +CommandProc CmdSellShareInCompany; +CommandProc CmdBuyCompany; + +CommandProc CmdFoundTown; +CommandProc CmdRenameTown; +CommandProc CmdDoTownAction; +CommandProc CmdTownGrowthRate; +CommandProc CmdTownCargoGoal; +CommandProc CmdTownSetText; +CommandProc CmdExpandTown; +CommandProc CmdDeleteTown; + +CommandProc CmdChangeSetting; +CommandProc CmdChangeCompanySetting; + +CommandProc CmdOrderRefit; +CommandProc CmdCloneOrder; + +CommandProc CmdClearArea; + +CommandProc CmdGiveMoney; +CommandProc CmdMoneyCheat; +CommandProc CmdChangeBankBalance; +CommandProc CmdBuildCanal; +CommandProc CmdBuildLock; + +CommandProc CmdCreateSubsidy; +CommandProc CmdCompanyCtrl; +CommandProc CmdCustomNewsItem; +CommandProc CmdCreateGoal; +CommandProc CmdRemoveGoal; +CommandProc CmdSetGoalText; +CommandProc CmdSetGoalProgress; +CommandProc CmdSetGoalCompleted; +CommandProc CmdGoalQuestion; +CommandProc CmdGoalQuestionAnswer; +CommandProc CmdCreateStoryPage; +CommandProc CmdCreateStoryPageElement; +CommandProc CmdUpdateStoryPageElement; +CommandProc CmdSetStoryPageTitle; +CommandProc CmdSetStoryPageDate; +CommandProc CmdShowStoryPage; +CommandProc CmdRemoveStoryPage; +CommandProc CmdRemoveStoryPageElement; + +CommandProc CmdLevelLand; + +CommandProc CmdBuildSignalTrack; +CommandProc CmdRemoveSignalTrack; + +CommandProc CmdSetAutoReplace; + +CommandProc CmdCloneVehicle; +CommandProc CmdStartStopVehicle; +CommandProc CmdMassStartStopVehicle; +CommandProc CmdAutoreplaceVehicle; +CommandProc CmdDepotSellAllVehicles; +CommandProc CmdDepotMassAutoReplace; + +CommandProc CmdCreateGroup; +CommandProc CmdAlterGroup; +CommandProc CmdDeleteGroup; +CommandProc CmdAddVehicleGroup; +CommandProc CmdAddSharedVehicleGroup; +CommandProc CmdRemoveAllVehiclesGroup; +CommandProc CmdSetGroupReplaceProtection; + +CommandProc CmdMoveOrder; +CommandProc CmdChangeTimetable; +CommandProc CmdSetVehicleOnTime; +CommandProc CmdAutofillTimetable; +CommandProc CmdAutomateTimetable; +CommandProc CmdSetTimetableStart; + +CommandProc CmdOpenCloseAirport; + +#define DEF_CMD(proc, flags, type) {proc, #proc, (CommandFlags)flags, type} + +/** + * The master command table + * + * This table contains all possible CommandProc functions with + * the flags which belongs to it. The indices are the same + * as the value from the CMD_* enums. + */ +static const Command _command_proc_table[] = { + DEF_CMD(CmdBuildRailroadTrack, CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_RAILROAD_TRACK + DEF_CMD(CmdRemoveRailroadTrack, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_REMOVE_RAILROAD_TRACK + DEF_CMD(CmdBuildSingleRail, CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_SINGLE_RAIL + DEF_CMD(CmdRemoveSingleRail, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_REMOVE_SINGLE_RAIL + DEF_CMD(CmdLandscapeClear, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_LANDSCAPE_CLEAR + DEF_CMD(CmdBuildBridge, CMD_DEITY | CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_BRIDGE + DEF_CMD(CmdBuildRailStation, CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_RAIL_STATION + DEF_CMD(CmdBuildTrainDepot, CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_TRAIN_DEPOT + DEF_CMD(CmdBuildSingleSignal, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_SIGNALS + DEF_CMD(CmdRemoveSingleSignal, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_REMOVE_SIGNALS + DEF_CMD(CmdTerraformLand, CMD_ALL_TILES | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_TERRAFORM_LAND + DEF_CMD(CmdBuildObject, CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_OBJECT + DEF_CMD(CmdBuildTunnel, CMD_DEITY | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_TUNNEL + DEF_CMD(CmdRemoveFromRailStation, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_REMOVE_FROM_RAIL_STATION + DEF_CMD(CmdConvertRail, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_CONVERT_RAILD + DEF_CMD(CmdBuildRailWaypoint, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_RAIL_WAYPOINT + DEF_CMD(CmdRenameWaypoint, 0, CMDT_OTHER_MANAGEMENT ), // CMD_RENAME_WAYPOINT + DEF_CMD(CmdRemoveFromRailWaypoint, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_REMOVE_FROM_RAIL_WAYPOINT + + DEF_CMD(CmdBuildRoadStop, CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_ROAD_STOP + DEF_CMD(CmdRemoveRoadStop, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_REMOVE_ROAD_STOP + DEF_CMD(CmdBuildLongRoad,CMD_DEITY | CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_LONG_ROAD + DEF_CMD(CmdRemoveLongRoad, CMD_NO_TEST | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_REMOVE_LONG_ROAD; towns may disallow removing road bits (as they are connected) in test, but in exec they're removed and thus removing is allowed. + DEF_CMD(CmdBuildRoad, CMD_DEITY | CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_ROAD + DEF_CMD(CmdBuildRoadDepot, CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_ROAD_DEPOT + + DEF_CMD(CmdBuildAirport, CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_AIRPORT + DEF_CMD(CmdBuildDock, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_DOCK + DEF_CMD(CmdBuildShipDepot, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_SHIP_DEPOT + DEF_CMD(CmdBuildBuoy, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_BUOY + DEF_CMD(CmdPlantTree, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_PLANT_TREE + + DEF_CMD(CmdBuildVehicle, CMD_CLIENT_ID, CMDT_VEHICLE_CONSTRUCTION ), // CMD_BUILD_VEHICLE + DEF_CMD(CmdSellVehicle, CMD_CLIENT_ID, CMDT_VEHICLE_CONSTRUCTION ), // CMD_SELL_VEHICLE + DEF_CMD(CmdRefitVehicle, 0, CMDT_VEHICLE_CONSTRUCTION ), // CMD_REFIT_VEHICLE + DEF_CMD(CmdSendVehicleToDepot, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_SEND_VEHICLE_TO_DEPOT + DEF_CMD(CmdSetVehicleVisibility, 0, CMDT_COMPANY_SETTING ), // CMD_SET_VEHICLE_VISIBILITY + + DEF_CMD(CmdMoveRailVehicle, 0, CMDT_VEHICLE_CONSTRUCTION ), // CMD_MOVE_RAIL_VEHICLE + DEF_CMD(CmdForceTrainProceed, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_FORCE_TRAIN_PROCEED + DEF_CMD(CmdReverseTrainDirection, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_REVERSE_TRAIN_DIRECTION + + DEF_CMD(CmdClearOrderBackup, CMD_CLIENT_ID, CMDT_SERVER_SETTING ), // CMD_CLEAR_ORDER_BACKUP + DEF_CMD(CmdModifyOrder, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_MODIFY_ORDER + DEF_CMD(CmdSkipToOrder, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SKIP_TO_ORDER + DEF_CMD(CmdDeleteOrder, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_DELETE_ORDER + DEF_CMD(CmdInsertOrder, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_INSERT_ORDER + + DEF_CMD(CmdChangeServiceInt, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_CHANGE_SERVICE_INT + + DEF_CMD(CmdBuildIndustry, CMD_DEITY, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_INDUSTRY + DEF_CMD(CmdSetCompanyManagerFace, 0, CMDT_OTHER_MANAGEMENT ), // CMD_SET_COMPANY_MANAGER_FACE + DEF_CMD(CmdSetCompanyColour, 0, CMDT_OTHER_MANAGEMENT ), // CMD_SET_COMPANY_COLOUR + + DEF_CMD(CmdIncreaseLoan, 0, CMDT_MONEY_MANAGEMENT ), // CMD_INCREASE_LOAN + DEF_CMD(CmdDecreaseLoan, 0, CMDT_MONEY_MANAGEMENT ), // CMD_DECREASE_LOAN + + DEF_CMD(CmdWantEnginePreview, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_WANT_ENGINE_PREVIEW + + DEF_CMD(CmdRenameVehicle, 0, CMDT_OTHER_MANAGEMENT ), // CMD_RENAME_VEHICLE + DEF_CMD(CmdRenameEngine, CMD_SERVER, CMDT_OTHER_MANAGEMENT ), // CMD_RENAME_ENGINE + + DEF_CMD(CmdRenameCompany, 0, CMDT_OTHER_MANAGEMENT ), // CMD_RENAME_COMPANY + DEF_CMD(CmdRenamePresident, 0, CMDT_OTHER_MANAGEMENT ), // CMD_RENAME_PRESIDENT + + DEF_CMD(CmdRenameStation, 0, CMDT_OTHER_MANAGEMENT ), // CMD_RENAME_STATION + DEF_CMD(CmdRenameDepot, 0, CMDT_OTHER_MANAGEMENT ), // CMD_RENAME_DEPOT + + DEF_CMD(CmdPlaceSign, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_PLACE_SIGN + DEF_CMD(CmdRenameSign, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_RENAME_SIGN + + DEF_CMD(CmdTurnRoadVeh, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_TURN_ROADVEH + + DEF_CMD(CmdPause, CMD_SERVER, CMDT_SERVER_SETTING ), // CMD_PAUSE + + DEF_CMD(CmdBuyShareInCompany, 0, CMDT_MONEY_MANAGEMENT ), // CMD_BUY_SHARE_IN_COMPANY + DEF_CMD(CmdSellShareInCompany, 0, CMDT_MONEY_MANAGEMENT ), // CMD_SELL_SHARE_IN_COMPANY + DEF_CMD(CmdBuyCompany, 0, CMDT_MONEY_MANAGEMENT ), // CMD_BUY_COMANY + + DEF_CMD(CmdFoundTown, CMD_DEITY | CMD_NO_TEST, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_FOUND_TOWN; founding random town can fail only in exec run + DEF_CMD(CmdRenameTown, CMD_DEITY | CMD_SERVER, CMDT_OTHER_MANAGEMENT ), // CMD_RENAME_TOWN + DEF_CMD(CmdDoTownAction, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_DO_TOWN_ACTION + DEF_CMD(CmdTownCargoGoal, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_TOWN_CARGO_GOAL + DEF_CMD(CmdTownGrowthRate, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_TOWN_GROWTH_RATE + DEF_CMD(CmdTownSetText, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_TOWN_SET_TEXT + DEF_CMD(CmdExpandTown, CMD_DEITY, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_EXPAND_TOWN + DEF_CMD(CmdDeleteTown, CMD_OFFLINE, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_DELETE_TOWN + + DEF_CMD(CmdOrderRefit, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_ORDER_REFIT + DEF_CMD(CmdCloneOrder, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_CLONE_ORDER + + DEF_CMD(CmdClearArea, CMD_NO_TEST, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_CLEAR_AREA; destroying multi-tile houses makes town rating differ between test and execution + + DEF_CMD(CmdMoneyCheat, CMD_OFFLINE, CMDT_CHEAT ), // CMD_MONEY_CHEAT + DEF_CMD(CmdChangeBankBalance, CMD_DEITY, CMDT_MONEY_MANAGEMENT ), // CMD_CHANGE_BANK_BALANCE + DEF_CMD(CmdBuildCanal, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_CANAL + DEF_CMD(CmdCreateSubsidy, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_CREATE_SUBSIDY + DEF_CMD(CmdCompanyCtrl, CMD_SPECTATOR | CMD_CLIENT_ID, CMDT_SERVER_SETTING ), // CMD_COMPANY_CTRL + DEF_CMD(CmdCustomNewsItem, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_CUSTOM_NEWS_ITEM + DEF_CMD(CmdCreateGoal, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_CREATE_GOAL + DEF_CMD(CmdRemoveGoal, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_REMOVE_GOAL + DEF_CMD(CmdSetGoalText, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_SET_GOAL_TEXT + DEF_CMD(CmdSetGoalProgress, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_SET_GOAL_PROGRESS + DEF_CMD(CmdSetGoalCompleted, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_SET_GOAL_COMPLETED + DEF_CMD(CmdGoalQuestion, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_GOAL_QUESTION + DEF_CMD(CmdGoalQuestionAnswer, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_GOAL_QUESTION_ANSWER + DEF_CMD(CmdCreateStoryPage, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_CREATE_STORY_PAGE + DEF_CMD(CmdCreateStoryPageElement, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_CREATE_STORY_PAGE_ELEMENT + DEF_CMD(CmdUpdateStoryPageElement, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_UPDATE_STORY_PAGE_ELEMENT + DEF_CMD(CmdSetStoryPageTitle, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_SET_STORY_PAGE_TITLE + DEF_CMD(CmdSetStoryPageDate, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_SET_STORY_PAGE_DATE + DEF_CMD(CmdShowStoryPage, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_SHOW_STORY_PAGE + DEF_CMD(CmdRemoveStoryPage, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_REMOVE_STORY_PAGE + DEF_CMD(CmdRemoveStoryPageElement, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_REMOVE_STORY_ELEMENT_PAGE + + DEF_CMD(CmdLevelLand, CMD_ALL_TILES | CMD_NO_TEST | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_LEVEL_LAND; test run might clear tiles multiple times, in execution that only happens once + + DEF_CMD(CmdBuildLock, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_LOCK + + DEF_CMD(CmdBuildSignalTrack, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_SIGNAL_TRACK + DEF_CMD(CmdRemoveSignalTrack, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_REMOVE_SIGNAL_TRACK + + DEF_CMD(CmdGiveMoney, 0, CMDT_MONEY_MANAGEMENT ), // CMD_GIVE_MONEY + DEF_CMD(CmdChangeSetting, CMD_SERVER, CMDT_SERVER_SETTING ), // CMD_CHANGE_SETTING + DEF_CMD(CmdChangeCompanySetting, 0, CMDT_COMPANY_SETTING ), // CMD_CHANGE_COMPANY_SETTING + DEF_CMD(CmdSetAutoReplace, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_SET_AUTOREPLACE + DEF_CMD(CmdCloneVehicle, CMD_NO_TEST, CMDT_VEHICLE_CONSTRUCTION ), // CMD_CLONE_VEHICLE; NewGRF callbacks influence building and refitting making it impossible to correctly estimate the cost + DEF_CMD(CmdStartStopVehicle, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_START_STOP_VEHICLE + DEF_CMD(CmdMassStartStopVehicle, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_MASS_START_STOP + DEF_CMD(CmdAutoreplaceVehicle, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_AUTOREPLACE_VEHICLE + DEF_CMD(CmdDepotSellAllVehicles, 0, CMDT_VEHICLE_CONSTRUCTION ), // CMD_DEPOT_SELL_ALL_VEHICLES + DEF_CMD(CmdDepotMassAutoReplace, 0, CMDT_VEHICLE_CONSTRUCTION ), // CMD_DEPOT_MASS_AUTOREPLACE + DEF_CMD(CmdCreateGroup, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_CREATE_GROUP + DEF_CMD(CmdDeleteGroup, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_DELETE_GROUP + DEF_CMD(CmdAlterGroup, 0, CMDT_OTHER_MANAGEMENT ), // CMD_ALTER_GROUP + DEF_CMD(CmdAddVehicleGroup, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_ADD_VEHICLE_GROUP + DEF_CMD(CmdAddSharedVehicleGroup, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_ADD_SHARE_VEHICLE_GROUP + DEF_CMD(CmdRemoveAllVehiclesGroup, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_REMOVE_ALL_VEHICLES_GROUP + DEF_CMD(CmdSetGroupReplaceProtection, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_GROUP_REPLACE_PROTECTION + DEF_CMD(CmdMoveOrder, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_MOVE_ORDER + DEF_CMD(CmdChangeTimetable, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_CHANGE_TIMETABLE + DEF_CMD(CmdSetVehicleOnTime, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_VEHICLE_ON_TIME + DEF_CMD(CmdAutofillTimetable, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_AUTOFILL_TIMETABLE + DEF_CMD(CmdAutomateTimetable, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_AUTOMATE_TIMETABLE + DEF_CMD(CmdSetTimetableStart, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_TIMETABLE_START + + DEF_CMD(CmdOpenCloseAirport, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_OPEN_CLOSE_AIRPORT +}; + +/*! + * This function range-checks a cmd, and checks if the cmd is not NULL + * + * @param cmd The integer value of a command + * @return true if the command is valid (and got a CommandProc function) + */ +bool IsValidCommand(uint32 cmd) +{ + cmd &= CMD_ID_MASK; + + return cmd < lengthof(_command_proc_table) && _command_proc_table[cmd].proc != NULL; +} + +/*! + * This function mask the parameter with CMD_ID_MASK and returns + * the flags which belongs to the given command. + * + * @param cmd The integer value of the command + * @return The flags for this command + */ +CommandFlags GetCommandFlags(uint32 cmd) +{ + assert(IsValidCommand(cmd)); + + return _command_proc_table[cmd & CMD_ID_MASK].flags; +} + +/*! + * This function mask the parameter with CMD_ID_MASK and returns + * the name which belongs to the given command. + * + * @param cmd The integer value of the command + * @return The name for this command + */ +const char *GetCommandName(uint32 cmd) +{ + assert(IsValidCommand(cmd)); + + return _command_proc_table[cmd & CMD_ID_MASK].name; +} + +/** + * Returns whether the command is allowed while the game is paused. + * @param cmd The command to check. + * @return True if the command is allowed while paused, false otherwise. + */ +bool IsCommandAllowedWhilePaused(uint32 cmd) +{ + /* Lookup table for the command types that are allowed for a given pause level setting. */ + static const int command_type_lookup[] = { + CMDPL_ALL_ACTIONS, ///< CMDT_LANDSCAPE_CONSTRUCTION + CMDPL_NO_LANDSCAPING, ///< CMDT_VEHICLE_CONSTRUCTION + CMDPL_NO_LANDSCAPING, ///< CMDT_MONEY_MANAGEMENT + CMDPL_NO_CONSTRUCTION, ///< CMDT_VEHICLE_MANAGEMENT + CMDPL_NO_CONSTRUCTION, ///< CMDT_ROUTE_MANAGEMENT + CMDPL_NO_CONSTRUCTION, ///< CMDT_OTHER_MANAGEMENT + CMDPL_NO_CONSTRUCTION, ///< CMDT_COMPANY_SETTING + CMDPL_NO_ACTIONS, ///< CMDT_SERVER_SETTING + CMDPL_NO_ACTIONS, ///< CMDT_CHEAT + }; + assert_compile(lengthof(command_type_lookup) == CMDT_END); + + assert(IsValidCommand(cmd)); + return _game_mode == GM_EDITOR || command_type_lookup[_command_proc_table[cmd & CMD_ID_MASK].type] <= _settings_game.construction.command_pause_level; +} + + +static int _docommand_recursive = 0; + +/** + * Shorthand for calling the long DoCommand with a container. + * + * @param container Container with (almost) all information + * @param flags Flags for the command and how to execute the command + * @see CommandProc + * @return the cost + */ +CommandCost DoCommand(const CommandContainer *container, DoCommandFlag flags) +{ + return DoCommand(container->tile, container->p1, container->p2, flags, container->cmd & CMD_ID_MASK, container->text); +} + +/*! + * This function executes a given command with the parameters from the #CommandProc parameter list. + * Depending on the flags parameter it execute or test a command. + * + * @param tile The tile to apply the command on (for the #CommandProc) + * @param p1 Additional data for the command (for the #CommandProc) + * @param p2 Additional data for the command (for the #CommandProc) + * @param flags Flags for the command and how to execute the command + * @param cmd The command-id to execute (a value of the CMD_* enums) + * @param text The text to pass + * @see CommandProc + * @return the cost + */ +CommandCost DoCommand(TileIndex tile, uint32 p1, uint32 p2, DoCommandFlag flags, uint32 cmd, const char *text) +{ + CommandCost res; + + /* Do not even think about executing out-of-bounds tile-commands */ + if (tile != 0 && (tile >= MapSize() || (!IsValidTile(tile) && (flags & DC_ALL_TILES) == 0))) return CMD_ERROR; + + /* Chop of any CMD_MSG or other flags; we don't need those here */ + CommandProc *proc = _command_proc_table[cmd & CMD_ID_MASK].proc; + + _docommand_recursive++; + + /* only execute the test call if it's toplevel, or we're not execing. */ + if (_docommand_recursive == 1 || !(flags & DC_EXEC) ) { + if (_docommand_recursive == 1) _cleared_object_areas.Clear(); + SetTownRatingTestMode(true); + res = proc(tile, flags & ~DC_EXEC, p1, p2, text); + SetTownRatingTestMode(false); + if (res.Failed()) { + goto error; + } + + if (_docommand_recursive == 1 && + !(flags & DC_QUERY_COST) && + !(flags & DC_BANKRUPT) && + !CheckCompanyHasMoney(res)) { // CheckCompanyHasMoney() modifies 'res' to an error if it fails. + goto error; + } + + if (!(flags & DC_EXEC)) { + _docommand_recursive--; + return res; + } + } + + /* Execute the command here. All cost-relevant functions set the expenses type + * themselves to the cost object at some point */ + if (_docommand_recursive == 1) _cleared_object_areas.Clear(); + res = proc(tile, flags, p1, p2, text); + if (res.Failed()) { +error: + _docommand_recursive--; + return res; + } + + /* if toplevel, subtract the money. */ + if (--_docommand_recursive == 0 && !(flags & DC_BANKRUPT)) { + SubtractMoneyFromCompany(res); + } + + return res; +} + +/*! + * This functions returns the money which can be used to execute a command. + * This is either the money of the current company or INT64_MAX if there + * is no such a company "at the moment" like the server itself. + * + * @return The available money of a company or INT64_MAX + */ +Money GetAvailableMoneyForCommand() +{ + CompanyID company = _current_company; + if (!Company::IsValidID(company)) return INT64_MAX; + return Company::Get(company)->money; +} + +/** + * Shortcut for the long DoCommandP when having a container with the data. + * @param container the container with information. + * @param my_cmd indicator if the command is from a company or server (to display error messages for a user) + * @return true if the command succeeded, else false + */ +bool DoCommandP(const CommandContainer *container, bool my_cmd) +{ + return DoCommandP(container->tile, container->p1, container->p2, container->cmd, container->callback, container->text, my_cmd); +} + +/*! + * Toplevel network safe docommand function for the current company. Must not be called recursively. + * The callback is called when the command succeeded or failed. The parameters + * \a tile, \a p1, and \a p2 are from the #CommandProc function. The parameter \a cmd is the command to execute. + * The parameter \a my_cmd is used to indicate if the command is from a company or the server. + * + * @param tile The tile to perform a command on (see #CommandProc) + * @param p1 Additional data for the command (see #CommandProc) + * @param p2 Additional data for the command (see #CommandProc) + * @param cmd The command to execute (a CMD_* value) + * @param callback A callback function to call after the command is finished + * @param text The text to pass + * @param my_cmd indicator if the command is from a company or server (to display error messages for a user) + * @return \c true if the command succeeded, else \c false. + */ +bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd) +{ + /* Cost estimation is generally only done when the + * local user presses shift while doing somthing. + * However, in case of incoming network commands, + * map generation or the pause button we do want + * to execute. */ + bool estimate_only = _shift_pressed && IsLocalCompany() && + !_generating_world && + !(cmd & CMD_NETWORK_COMMAND) && + (cmd & CMD_ID_MASK) != CMD_PAUSE; + + /* We're only sending the command, so don't do + * fancy things for 'success'. */ + bool only_sending = _networking && !(cmd & CMD_NETWORK_COMMAND); + + /* Where to show the message? */ + int x = TileX(tile) * TILE_SIZE; + int y = TileY(tile) * TILE_SIZE; + + if (_pause_mode != PM_UNPAUSED && !IsCommandAllowedWhilePaused(cmd)) { + ShowErrorMessage(GB(cmd, 16, 16), STR_ERROR_NOT_ALLOWED_WHILE_PAUSED, WL_INFO, x, y); + return false; + } + +#ifdef ENABLE_NETWORK + /* Only set p2 when the command does not come from the network. */ + if (!(cmd & CMD_NETWORK_COMMAND) && GetCommandFlags(cmd) & CMD_CLIENT_ID && p2 == 0) p2 = CLIENT_ID_SERVER; +#endif + + CommandCost res = DoCommandPInternal(tile, p1, p2, cmd, callback, text, my_cmd, estimate_only); + if (res.Failed()) { + /* Only show the error when it's for us. */ + StringID error_part1 = GB(cmd, 16, 16); + if (estimate_only || (IsLocalCompany() && error_part1 != 0 && my_cmd)) { + ShowErrorMessage(error_part1, res.GetErrorMessage(), WL_INFO, x, y, res.GetTextRefStackGRF(), res.GetTextRefStackSize(), res.GetTextRefStack()); + } + } else if (estimate_only) { + ShowEstimatedCostOrIncome(res.GetCost(), x, y); + } else if (!only_sending && res.GetCost() != 0 && tile != 0 && IsLocalCompany() && _game_mode != GM_EDITOR) { + /* Only show the cost animation when we did actually + * execute the command, i.e. we're not sending it to + * the server, when it has cost the local company + * something. Furthermore in the editor there is no + * concept of cost, so don't show it there either. */ + ShowCostOrIncomeAnimation(x, y, GetSlopePixelZ(x, y), res.GetCost()); + } + + if (!estimate_only && !only_sending && callback != NULL) { + callback(res, tile, p1, p2); + } + + return res.Succeeded(); +} + + +/** + * Helper to deduplicate the code for returning. + * @param cmd the command cost to return. + * @param clear whether to keep the storage changes or not. + */ +#define return_dcpi(cmd) { _docommand_recursive = 0; return cmd; } + +/*! + * Helper function for the toplevel network safe docommand function for the current company. + * + * @param tile The tile to perform a command on (see #CommandProc) + * @param p1 Additional data for the command (see #CommandProc) + * @param p2 Additional data for the command (see #CommandProc) + * @param cmd The command to execute (a CMD_* value) + * @param callback A callback function to call after the command is finished + * @param text The text to pass + * @param my_cmd indicator if the command is from a company or server (to display error messages for a user) + * @param estimate_only whether to give only the estimate or also execute the command + * @return the command cost of this function. + */ +CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd, bool estimate_only) +{ + /* Prevent recursion; it gives a mess over the network */ + assert(_docommand_recursive == 0); + _docommand_recursive = 1; + + /* Reset the state. */ + _additional_cash_required = 0; + + /* Get pointer to command handler */ + byte cmd_id = cmd & CMD_ID_MASK; + assert(cmd_id < lengthof(_command_proc_table)); + + CommandProc *proc = _command_proc_table[cmd_id].proc; + /* Shouldn't happen, but you never know when someone adds + * NULLs to the _command_proc_table. */ + assert(proc != NULL); + + /* Command flags are used internally */ + CommandFlags cmd_flags = GetCommandFlags(cmd); + /* Flags get send to the DoCommand */ + DoCommandFlag flags = CommandFlagsToDCFlags(cmd_flags); + +#ifdef ENABLE_NETWORK + /* Make sure p2 is properly set to a ClientID. */ + assert(!(cmd_flags & CMD_CLIENT_ID) || p2 != 0); +#endif + + /* Do not even think about executing out-of-bounds tile-commands */ + if (tile != 0 && (tile >= MapSize() || (!IsValidTile(tile) && (cmd_flags & CMD_ALL_TILES) == 0))) return_dcpi(CMD_ERROR); + + /* Always execute server and spectator commands as spectator */ + bool exec_as_spectator = (cmd_flags & (CMD_SPECTATOR | CMD_SERVER)) != 0; + + /* If the company isn't valid it may only do server command or start a new company! + * The server will ditch any server commands a client sends to it, so effectively + * this guards the server from executing functions for an invalid company. */ + if (_game_mode == GM_NORMAL && !exec_as_spectator && !Company::IsValidID(_current_company) && !(_current_company == OWNER_DEITY && (cmd_flags & CMD_DEITY) != 0)) { + return_dcpi(CMD_ERROR); + } + + Backup cur_company(_current_company, FILE_LINE); + if (exec_as_spectator) cur_company.Change(COMPANY_SPECTATOR); + + bool test_and_exec_can_differ = (cmd_flags & CMD_NO_TEST) != 0; + + /* Test the command. */ + _cleared_object_areas.Clear(); + SetTownRatingTestMode(true); + BasePersistentStorageArray::SwitchMode(PSM_ENTER_TESTMODE); + CommandCost res = proc(tile, flags, p1, p2, text); + BasePersistentStorageArray::SwitchMode(PSM_LEAVE_TESTMODE); + SetTownRatingTestMode(false); + + /* Make sure we're not messing things up here. */ + assert(exec_as_spectator ? _current_company == COMPANY_SPECTATOR : cur_company.Verify()); + + /* If the command fails, we're doing an estimate + * or the player does not have enough money + * (unless it's a command where the test and + * execution phase might return different costs) + * we bail out here. */ + if (res.Failed() || estimate_only || + (!test_and_exec_can_differ && !CheckCompanyHasMoney(res))) { + if (!_networking || _generating_world || (cmd & CMD_NETWORK_COMMAND) != 0) { + /* Log the failed command as well. Just to be able to be find + * causes of desyncs due to bad command test implementations. */ + DEBUG(desync, 1, "cmdf: %08x; %02x; %02x; %06x; %08x; %08x; %08x; \"%s\" (%s)", _date, _date_fract, (int)_current_company, tile, p1, p2, cmd & ~CMD_NETWORK_COMMAND, text, GetCommandName(cmd)); + } + cur_company.Restore(); + return_dcpi(res); + } + +#ifdef ENABLE_NETWORK + /* + * If we are in network, and the command is not from the network + * send it to the command-queue and abort execution + */ + if (_networking && !_generating_world && !(cmd & CMD_NETWORK_COMMAND)) { + NetworkSendCommand(tile, p1, p2, cmd & ~CMD_FLAGS_MASK, callback, text, _current_company); + cur_company.Restore(); + + /* Don't return anything special here; no error, no costs. + * This way it's not handled by DoCommand and only the + * actual execution of the command causes messages. Also + * reset the storages as we've not executed the command. */ + return_dcpi(CommandCost()); + } +#endif /* ENABLE_NETWORK */ + DEBUG(desync, 1, "cmd: %08x; %02x; %02x; %06x; %08x; %08x; %08x; \"%s\" (%s)", _date, _date_fract, (int)_current_company, tile, p1, p2, cmd & ~CMD_NETWORK_COMMAND, text, GetCommandName(cmd)); + + /* Actually try and execute the command. If no cost-type is given + * use the construction one */ + _cleared_object_areas.Clear(); + BasePersistentStorageArray::SwitchMode(PSM_ENTER_COMMAND); + CommandCost res2 = proc(tile, flags | DC_EXEC, p1, p2, text); + BasePersistentStorageArray::SwitchMode(PSM_LEAVE_COMMAND); + + if (cmd_id == CMD_COMPANY_CTRL) { + cur_company.Trash(); + /* We are a new company -> Switch to new local company. + * We were closed down -> Switch to spectator + * Some other company opened/closed down -> The outside function will switch back */ + _current_company = _local_company; + } else { + /* Make sure nothing bad happened, like changing the current company. */ + assert(exec_as_spectator ? _current_company == COMPANY_SPECTATOR : cur_company.Verify()); + cur_company.Restore(); + } + + /* If the test and execution can differ we have to check the + * return of the command. Otherwise we can check whether the + * test and execution have yielded the same result, + * i.e. cost and error state are the same. */ + if (!test_and_exec_can_differ) { + assert(res.GetCost() == res2.GetCost() && res.Failed() == res2.Failed()); // sanity check + } else if (res2.Failed()) { + return_dcpi(res2); + } + + /* If we're needing more money and we haven't done + * anything yet, ask for the money! */ + if (_additional_cash_required != 0 && res2.GetCost() == 0) { + /* It could happen we removed rail, thus gained money, and deleted something else. + * So make sure the signal buffer is empty even in this case */ + UpdateSignalsInBuffer(); + SetDParam(0, _additional_cash_required); + return_dcpi(CommandCost(STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY)); + } + + /* update last build coordinate of company. */ + if (tile != 0) { + Company *c = Company::GetIfValid(_current_company); + if (c != NULL) c->last_build_coordinate = tile; + } + + /* Send Tile Number to Watching Company Windows */ + int watching_window = 0; + WatchCompany *wc; + wc = dynamic_cast(FindWindowById(WC_WATCH_COMPANY, watching_window)); + while (wc!=NULL) { + wc->OnDoCommand( _current_company, tile ); + watching_window++; + wc = dynamic_cast(FindWindowById(WC_WATCH_COMPANY, watching_window)); + } + + SubtractMoneyFromCompany(res2); + + /* update signals if needed */ + UpdateSignalsInBuffer(); + + return_dcpi(res2); +} +#undef return_dcpi + + +/** + * Adds the cost of the given command return value to this cost. + * Also takes a possible error message when it is set. + * @param ret The command to add the cost of. + */ +void CommandCost::AddCost(const CommandCost &ret) +{ + this->AddCost(ret.cost); + if (this->success && !ret.success) { + this->message = ret.message; + this->success = false; + } +} + +/** + * Values to put on the #TextRefStack for the error message. + * There is only one static instance of the array, just like there is only one + * instance of normal DParams. + */ +uint32 CommandCost::textref_stack[16]; + +/** + * Activate usage of the NewGRF #TextRefStack for the error message. + * @param grffile NewGRF that provides the #TextRefStack + * @param num_registers number of entries to copy from the temporary NewGRF registers + */ +void CommandCost::UseTextRefStack(const GRFFile *grffile, uint num_registers) +{ + extern TemporaryStorageArray _temp_store; + + assert(num_registers < lengthof(textref_stack)); + this->textref_stack_grffile = grffile; + this->textref_stack_size = num_registers; + for (uint i = 0; i < num_registers; i++) { + textref_stack[i] = _temp_store.GetValue(0x100 + i); + } +} diff --git a/src/command_func.h b/src/command_func.h new file mode 100644 index 0000000..c4cc51e --- /dev/null +++ b/src/command_func.h @@ -0,0 +1,128 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file command_func.h Functions related to commands. */ + +#ifndef COMMAND_FUNC_H +#define COMMAND_FUNC_H + +#include "command_type.h" +#include "company_type.h" + +/** + * Define a default return value for a failed command. + * + * This variable contains a CommandCost object with is declared as "failed". + * Other functions just need to return this error if there is an error, + * which doesn't need to specific by a StringID. + */ +static const CommandCost CMD_ERROR = CommandCost(INVALID_STRING_ID); + +/** + * Returns from a function with a specific StringID as error. + * + * This macro is used to return from a function. The parameter contains the + * StringID which will be returned. + * + * @param errcode The StringID to return + */ +#define return_cmd_error(errcode) return CommandCost(errcode); + +CommandCost DoCommand(TileIndex tile, uint32 p1, uint32 p2, DoCommandFlag flags, uint32 cmd, const char *text = NULL); +CommandCost DoCommand(const CommandContainer *container, DoCommandFlag flags); + +bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback = NULL, const char *text = NULL, bool my_cmd = true); +bool DoCommandP(const CommandContainer *container, bool my_cmd = true); + +CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd, bool estimate_only); + +#ifdef ENABLE_NETWORK +void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, CompanyID company); +#endif /* ENABLE_NETWORK */ + +extern Money _additional_cash_required; + +bool IsValidCommand(uint32 cmd); +CommandFlags GetCommandFlags(uint32 cmd); +const char *GetCommandName(uint32 cmd); +Money GetAvailableMoneyForCommand(); +bool IsCommandAllowedWhilePaused(uint32 cmd); + +/** + * Extracts the DC flags needed for DoCommand from the flags returned by GetCommandFlags + * @param cmd_flags Flags from GetCommandFlags + * @return flags for DoCommand + */ +static inline DoCommandFlag CommandFlagsToDCFlags(CommandFlags cmd_flags) +{ + DoCommandFlag flags = DC_NONE; + if (cmd_flags & CMD_NO_WATER) flags |= DC_NO_WATER; + if (cmd_flags & CMD_AUTO) flags |= DC_AUTO; + if (cmd_flags & CMD_ALL_TILES) flags |= DC_ALL_TILES; + return flags; +} + +/*** All command callbacks that exist ***/ + +/* ai/ai_instance.cpp */ +CommandCallback CcAI; + +/* airport_gui.cpp */ +CommandCallback CcBuildAirport; + +/* bridge_gui.cpp */ +CommandCallback CcBuildBridge; + +/* dock_gui.cpp */ +CommandCallback CcBuildDocks; +CommandCallback CcBuildCanal; + +/* depot_gui.cpp */ +CommandCallback CcCloneVehicle; + +/* game/game_instance.cpp */ +CommandCallback CcGame; + +/* group_gui.cpp */ +CommandCallback CcCreateGroup; +CommandCallback CcAddVehicleNewGroup; + +/* industry_gui.cpp */ +CommandCallback CcBuildIndustry; + +/* main_gui.cpp */ +CommandCallback CcPlaySound10; +CommandCallback CcPlaceSign; +CommandCallback CcTerraform; +CommandCallback CcGiveMoney; + +/* rail_gui.cpp */ +CommandCallback CcPlaySound1E; +CommandCallback CcRailDepot; +CommandCallback CcStation; +CommandCallback CcBuildRailTunnel; + +/* road_gui.cpp */ +CommandCallback CcPlaySound1D; +CommandCallback CcBuildRoadTunnel; +CommandCallback CcRoadDepot; +CommandCallback CcRoadStop; + +/* train_gui.cpp */ +CommandCallback CcBuildWagon; + +/* town_gui.cpp */ +CommandCallback CcFoundTown; +CommandCallback CcFoundRandomTown; + +/* vehicle_gui.cpp */ +CommandCallback CcBuildPrimaryVehicle; +CommandCallback CcStartStopVehicle; + +#endif /* COMMAND_FUNC_H */ diff --git a/src/command_type.h b/src/command_type.h new file mode 100644 index 0000000..9aeeaf7 --- /dev/null +++ b/src/command_type.h @@ -0,0 +1,482 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file command_type.h Types related to commands. */ + +#ifndef COMMAND_TYPE_H +#define COMMAND_TYPE_H + +#include "economy_type.h" +#include "strings_type.h" +#include "tile_type.h" + +struct GRFFile; + +/** + * Common return value for all commands. Wraps the cost and + * a possible error message/state together. + */ +class CommandCost { + ExpensesType expense_type; ///< the type of expence as shown on the finances view + Money cost; ///< The cost of this action + StringID message; ///< Warning message for when success is unset + bool success; ///< Whether the comment went fine up to this moment + const GRFFile *textref_stack_grffile; ///< NewGRF providing the #TextRefStack content. + uint textref_stack_size; ///< Number of uint32 values to put on the #TextRefStack for the error message. + + static uint32 textref_stack[16]; + +public: + /** + * Creates a command cost return with no cost and no error + */ + CommandCost() : expense_type(INVALID_EXPENSES), cost(0), message(INVALID_STRING_ID), success(true), textref_stack_grffile(NULL), textref_stack_size(0) {} + + /** + * Creates a command return value the is failed with the given message + */ + explicit CommandCost(StringID msg) : expense_type(INVALID_EXPENSES), cost(0), message(msg), success(false), textref_stack_grffile(NULL), textref_stack_size(0) {} + + /** + * Creates a command cost with given expense type and start cost of 0 + * @param ex_t the expense type + */ + explicit CommandCost(ExpensesType ex_t) : expense_type(ex_t), cost(0), message(INVALID_STRING_ID), success(true), textref_stack_grffile(NULL), textref_stack_size(0) {} + + /** + * Creates a command return value with the given start cost and expense type + * @param ex_t the expense type + * @param cst the initial cost of this command + */ + CommandCost(ExpensesType ex_t, const Money &cst) : expense_type(ex_t), cost(cst), message(INVALID_STRING_ID), success(true), textref_stack_grffile(NULL), textref_stack_size(0) {} + + + /** + * Adds the given cost to the cost of the command. + * @param cost the cost to add + */ + inline void AddCost(const Money &cost) + { + this->cost += cost; + } + + void AddCost(const CommandCost &cmd_cost); + + /** + * Multiplies the cost of the command by the given factor. + * @param factor factor to multiply the costs with + */ + inline void MultiplyCost(int factor) + { + this->cost *= factor; + } + + /** + * The costs as made up to this moment + * @return the costs + */ + inline Money GetCost() const + { + return this->cost; + } + + /** + * The expense type of the cost + * @return the expense type + */ + inline ExpensesType GetExpensesType() const + { + return this->expense_type; + } + + /** + * Makes this #CommandCost behave like an error command. + * @param message The error message. + */ + void MakeError(StringID message) + { + assert(message != INVALID_STRING_ID); + this->success = false; + this->message = message; + } + + void UseTextRefStack(const GRFFile *grffile, uint num_registers); + + /** + * Returns the NewGRF providing the #TextRefStack of the error message. + * @return the NewGRF. + */ + const GRFFile *GetTextRefStackGRF() const + { + return this->textref_stack_grffile; + } + + /** + * Returns the number of uint32 values for the #TextRefStack of the error message. + * @return number of uint32 values. + */ + uint GetTextRefStackSize() const + { + return this->textref_stack_size; + } + + /** + * Returns a pointer to the values for the #TextRefStack of the error message. + * @return uint32 values for the #TextRefStack + */ + const uint32 *GetTextRefStack() const + { + return textref_stack; + } + + /** + * Returns the error message of a command + * @return the error message, if succeeded #INVALID_STRING_ID + */ + StringID GetErrorMessage() const + { + if (this->success) return INVALID_STRING_ID; + return this->message; + } + + /** + * Did this command succeed? + * @return true if and only if it succeeded + */ + inline bool Succeeded() const + { + return this->success; + } + + /** + * Did this command fail? + * @return true if and only if it failed + */ + inline bool Failed() const + { + return !this->success; + } +}; + +/** + * List of commands. + * + * This enum defines all possible commands which can be executed to the game + * engine. Observing the game like the query-tool or checking the profit of a + * vehicle don't result in a command which should be executed in the engine + * nor send to the server in a network game. + * + * @see _command_proc_table + */ +enum Commands { + CMD_BUILD_RAILROAD_TRACK, ///< build a rail track + CMD_REMOVE_RAILROAD_TRACK, ///< remove a rail track + CMD_BUILD_SINGLE_RAIL, ///< build a single rail track + CMD_REMOVE_SINGLE_RAIL, ///< remove a single rail track + CMD_LANDSCAPE_CLEAR, ///< demolish a tile + CMD_BUILD_BRIDGE, ///< build a bridge + CMD_BUILD_RAIL_STATION, ///< build a rail station + CMD_BUILD_TRAIN_DEPOT, ///< build a train depot + CMD_BUILD_SIGNALS, ///< build a signal + CMD_REMOVE_SIGNALS, ///< remove a signal + CMD_TERRAFORM_LAND, ///< terraform a tile + CMD_BUILD_OBJECT, ///< build an object + CMD_BUILD_TUNNEL, ///< build a tunnel + + CMD_REMOVE_FROM_RAIL_STATION, ///< remove a (rectangle of) tiles from a rail station + CMD_CONVERT_RAIL, ///< convert a rail type + + CMD_BUILD_RAIL_WAYPOINT, ///< build a waypoint + CMD_RENAME_WAYPOINT, ///< rename a waypoint + CMD_REMOVE_FROM_RAIL_WAYPOINT, ///< remove a (rectangle of) tiles from a rail waypoint + + CMD_BUILD_ROAD_STOP, ///< build a road stop + CMD_REMOVE_ROAD_STOP, ///< remove a road stop + CMD_BUILD_LONG_ROAD, ///< build a complete road (not a "half" one) + CMD_REMOVE_LONG_ROAD, ///< remove a complete road (not a "half" one) + CMD_BUILD_ROAD, ///< build a "half" road + CMD_BUILD_ROAD_DEPOT, ///< build a road depot + + CMD_BUILD_AIRPORT, ///< build an airport + + CMD_BUILD_DOCK, ///< build a dock + + CMD_BUILD_SHIP_DEPOT, ///< build a ship depot + CMD_BUILD_BUOY, ///< build a buoy + + CMD_PLANT_TREE, ///< plant a tree + + CMD_BUILD_VEHICLE, ///< build a vehicle + CMD_SELL_VEHICLE, ///< sell a vehicle + CMD_REFIT_VEHICLE, ///< refit the cargo space of a vehicle + CMD_SEND_VEHICLE_TO_DEPOT, ///< send a vehicle to a depot + CMD_SET_VEHICLE_VISIBILITY, ///< hide or unhide a vehicle in the build vehicle and autoreplace GUIs + + CMD_MOVE_RAIL_VEHICLE, ///< move a rail vehicle (in the depot) + CMD_FORCE_TRAIN_PROCEED, ///< proceed a train to pass a red signal + CMD_REVERSE_TRAIN_DIRECTION, ///< turn a train around + + CMD_CLEAR_ORDER_BACKUP, ///< clear the order backup of a given user/tile + CMD_MODIFY_ORDER, ///< modify an order (like set full-load) + CMD_SKIP_TO_ORDER, ///< skip an order to the next of specific one + CMD_DELETE_ORDER, ///< delete an order + CMD_INSERT_ORDER, ///< insert a new order + + CMD_CHANGE_SERVICE_INT, ///< change the server interval of a vehicle + + CMD_BUILD_INDUSTRY, ///< build a new industry + + CMD_SET_COMPANY_MANAGER_FACE, ///< set the manager's face of the company + CMD_SET_COMPANY_COLOUR, ///< set the colour of the company + + CMD_INCREASE_LOAN, ///< increase the loan from the bank + CMD_DECREASE_LOAN, ///< decrease the loan from the bank + + CMD_WANT_ENGINE_PREVIEW, ///< confirm the preview of an engine + + CMD_RENAME_VEHICLE, ///< rename a whole vehicle + CMD_RENAME_ENGINE, ///< rename a engine (in the engine list) + CMD_RENAME_COMPANY, ///< change the company name + CMD_RENAME_PRESIDENT, ///< change the president name + CMD_RENAME_STATION, ///< rename a station + CMD_RENAME_DEPOT, ///< rename a depot + + CMD_PLACE_SIGN, ///< place a sign + CMD_RENAME_SIGN, ///< rename a sign + + CMD_TURN_ROADVEH, ///< turn a road vehicle around + + CMD_PAUSE, ///< pause the game + + CMD_BUY_SHARE_IN_COMPANY, ///< buy a share from a company + CMD_SELL_SHARE_IN_COMPANY, ///< sell a share from a company + CMD_BUY_COMPANY, ///< buy a company which is bankrupt + + CMD_FOUND_TOWN, ///< found a town + CMD_RENAME_TOWN, ///< rename a town + CMD_DO_TOWN_ACTION, ///< do a action from the town detail window (like advertises or bribe) + CMD_TOWN_CARGO_GOAL, ///< set the goal of a cargo for a town + CMD_TOWN_GROWTH_RATE, ///< set the town growth rate + CMD_TOWN_SET_TEXT, ///< set the custom text of a town + CMD_EXPAND_TOWN, ///< expand a town + CMD_DELETE_TOWN, ///< delete a town + + CMD_ORDER_REFIT, ///< change the refit information of an order (for "goto depot" ) + CMD_CLONE_ORDER, ///< clone (and share) an order + CMD_CLEAR_AREA, ///< clear an area + + CMD_MONEY_CHEAT, ///< do the money cheat + CMD_CHANGE_BANK_BALANCE, ///< change bank balance to charge costs or give money from a GS + CMD_BUILD_CANAL, ///< build a canal + + CMD_CREATE_SUBSIDY, ///< create a new subsidy + CMD_COMPANY_CTRL, ///< used in multiplayer to create a new companies etc. + CMD_CUSTOM_NEWS_ITEM, ///< create a custom news message + CMD_CREATE_GOAL, ///< create a new goal + CMD_REMOVE_GOAL, ///< remove a goal + CMD_SET_GOAL_TEXT, ///< update goal text of a goal + CMD_SET_GOAL_PROGRESS, ///< update goal progress text of a goal + CMD_SET_GOAL_COMPLETED, ///< update goal completed status of a goal + CMD_GOAL_QUESTION, ///< ask a goal related question + CMD_GOAL_QUESTION_ANSWER, ///< answer(s) to CMD_GOAL_QUESTION + CMD_CREATE_STORY_PAGE, ///< create a new story page + CMD_CREATE_STORY_PAGE_ELEMENT, ///< create a new story page element + CMD_UPDATE_STORY_PAGE_ELEMENT, ///< update a story page element + CMD_SET_STORY_PAGE_TITLE, ///< update title of a story page + CMD_SET_STORY_PAGE_DATE, ///< update date of a story page + CMD_SHOW_STORY_PAGE, ///< show a story page + CMD_REMOVE_STORY_PAGE, ///< remove a story page + CMD_REMOVE_STORY_PAGE_ELEMENT, ///< remove a story page element + CMD_LEVEL_LAND, ///< level land + + CMD_BUILD_LOCK, ///< build a lock + + CMD_BUILD_SIGNAL_TRACK, ///< add signals along a track (by dragging) + CMD_REMOVE_SIGNAL_TRACK, ///< remove signals along a track (by dragging) + + CMD_GIVE_MONEY, ///< give money to another company + CMD_CHANGE_SETTING, ///< change a setting + CMD_CHANGE_COMPANY_SETTING, ///< change a company setting + + CMD_SET_AUTOREPLACE, ///< set an autoreplace entry + + CMD_CLONE_VEHICLE, ///< clone a vehicle + CMD_START_STOP_VEHICLE, ///< start or stop a vehicle + CMD_MASS_START_STOP, ///< start/stop all vehicles (in a depot) + CMD_AUTOREPLACE_VEHICLE, ///< replace/renew a vehicle while it is in a depot + CMD_DEPOT_SELL_ALL_VEHICLES, ///< sell all vehicles which are in a given depot + CMD_DEPOT_MASS_AUTOREPLACE, ///< force the autoreplace to take action in a given depot + + CMD_CREATE_GROUP, ///< create a new group + CMD_DELETE_GROUP, ///< delete a group + CMD_ALTER_GROUP, ///< alter a group + CMD_ADD_VEHICLE_GROUP, ///< add a vehicle to a group + CMD_ADD_SHARED_VEHICLE_GROUP, ///< add all other shared vehicles to a group which are missing + CMD_REMOVE_ALL_VEHICLES_GROUP, ///< remove all vehicles from a group + CMD_SET_GROUP_REPLACE_PROTECTION, ///< set the autoreplace-protection for a group + + CMD_MOVE_ORDER, ///< move an order + CMD_CHANGE_TIMETABLE, ///< change the timetable for a vehicle + CMD_SET_VEHICLE_ON_TIME, ///< set the vehicle on time feature (timetable) + CMD_AUTOFILL_TIMETABLE, ///< autofill the timetable + CMD_AUTOMATE_TIMETABLE, ///< automate the timetable + CMD_SET_TIMETABLE_START, ///< set the date that a timetable should start + + CMD_OPEN_CLOSE_AIRPORT, ///< open/close an airport to incoming aircraft + + CMD_END, ///< Must ALWAYS be on the end of this list!! (period) +}; + +/** + * List of flags for a command. + * + * This enums defines some flags which can be used for the commands. + */ +enum DoCommandFlag { + DC_NONE = 0x000, ///< no flag is set + DC_EXEC = 0x001, ///< execute the given command + DC_AUTO = 0x002, ///< don't allow building on structures + DC_QUERY_COST = 0x004, ///< query cost only, don't build. + DC_NO_WATER = 0x008, ///< don't allow building on water + DC_NO_RAIL_OVERLAP = 0x010, ///< don't allow overlap of rails (used in buildrail) + DC_NO_TEST_TOWN_RATING = 0x020, ///< town rating does not disallow you from building + DC_BANKRUPT = 0x040, ///< company bankrupts, skip money check, skip vehicle on tile check in some cases + DC_AUTOREPLACE = 0x080, ///< autoreplace/autorenew is in progress, this shall disable vehicle limits when building, and ignore certain restrictions when undoing things (like vehicle attach callback) + DC_NO_CARGO_CAP_CHECK = 0x100, ///< when autoreplace/autorenew is in progress, this shall prevent truncating the amount of cargo in the vehicle to prevent testing the command to remove cargo + DC_ALL_TILES = 0x200, ///< allow this command also on MP_VOID tiles + DC_NO_MODIFY_TOWN_RATING = 0x400, ///< do not change town rating + DC_FORCE_CLEAR_TILE = 0x800, ///< do not only remove the object on the tile, but also clear any water left on it +}; +DECLARE_ENUM_AS_BIT_SET(DoCommandFlag) + +/** + * Used to combine a StringID with the command. + * + * This macro can be used to add a StringID (the error message to show) on a command-id + * (CMD_xxx). Use the binary or-operator "|" to combine the command with the result from + * this macro. + * + * @param x The StringID to combine with a command-id + */ +#define CMD_MSG(x) ((x) << 16) + +/** + * Defines some flags. + * + * This enumeration defines some flags which are binary-or'ed on a command. + */ +enum FlaggedCommands { + CMD_NETWORK_COMMAND = 0x0100, ///< execute the command without sending it on the network + CMD_FLAGS_MASK = 0xFF00, ///< mask for all command flags + CMD_ID_MASK = 0x00FF, ///< mask for the command ID +}; + +/** + * Command flags for the command table _command_proc_table. + * + * This enumeration defines flags for the _command_proc_table. + */ +enum CommandFlags { + CMD_SERVER = 0x001, ///< the command can only be initiated by the server + CMD_SPECTATOR = 0x002, ///< the command may be initiated by a spectator + CMD_OFFLINE = 0x004, ///< the command cannot be executed in a multiplayer game; single-player only + CMD_AUTO = 0x008, ///< set the DC_AUTO flag on this command + CMD_ALL_TILES = 0x010, ///< allow this command also on MP_VOID tiles + CMD_NO_TEST = 0x020, ///< the command's output may differ between test and execute due to town rating changes etc. + CMD_NO_WATER = 0x040, ///< set the DC_NO_WATER flag on this command + CMD_CLIENT_ID = 0x080, ///< set p2 with the ClientID of the sending client. + CMD_DEITY = 0x100, ///< the command may be executed by COMPANY_DEITY + CMD_STR_CTRL = 0x200, ///< the command's string may contain control strings +}; +DECLARE_ENUM_AS_BIT_SET(CommandFlags) + +/** Types of commands we have. */ +enum CommandType { + CMDT_LANDSCAPE_CONSTRUCTION, ///< Construction and destruction of objects on the map. + CMDT_VEHICLE_CONSTRUCTION, ///< Construction, modification (incl. refit) and destruction of vehicles. + CMDT_MONEY_MANAGEMENT, ///< Management of money, i.e. loans and shares. + CMDT_VEHICLE_MANAGEMENT, ///< Stopping, starting, sending to depot, turning around, replace orders etc. + CMDT_ROUTE_MANAGEMENT, ///< Modifications to route management (orders, groups, etc). + CMDT_OTHER_MANAGEMENT, ///< Renaming stuff, changing company colours, placing signs, etc. + CMDT_COMPANY_SETTING, ///< Changing settings related to a company. + CMDT_SERVER_SETTING, ///< Pausing/removing companies/server settings. + CMDT_CHEAT, ///< A cheat of some sorts. + + CMDT_END, ///< Magic end marker. +}; + +/** Different command pause levels. */ +enum CommandPauseLevel { + CMDPL_NO_ACTIONS, ///< No user actions may be executed. + CMDPL_NO_CONSTRUCTION, ///< No construction actions may be executed. + CMDPL_NO_LANDSCAPING, ///< No landscaping actions may be executed. + CMDPL_ALL_ACTIONS, ///< All actions may be executed. +}; + +/** + * Defines the callback type for all command handler functions. + * + * This type defines the function header for all functions which handles a CMD_* command. + * A command handler use the parameters to act according to the meaning of the command. + * The tile parameter defines the tile to perform an action on. + * The flag parameter is filled with flags from the DC_* enumeration. The parameters + * p1 and p2 are filled with parameters for the command like "which road type", "which + * order" or "direction". Each function should mentioned in there doxygen comments + * the usage of these parameters. + * + * @param tile The tile to apply a command on + * @param flags Flags for the command, from the DC_* enumeration + * @param p1 Additional data for the command + * @param p2 Additional data for the command + * @param text Additional text + * @return The CommandCost of the command, which can be succeeded or failed. + */ +typedef CommandCost CommandProc(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text); + +/** + * Define a command with the flags which belongs to it. + * + * This struct connect a command handler function with the flags created with + * the #CMD_AUTO, #CMD_OFFLINE and #CMD_SERVER values. + */ +struct Command { + CommandProc *proc; ///< The procedure to actually executing + const char *name; ///< A human readable name for the procedure + CommandFlags flags; ///< The (command) flags to that apply to this command + CommandType type; ///< The type of command. +}; + +/** + * Define a callback function for the client, after the command is finished. + * + * Functions of this type are called after the command is finished. The parameters + * are from the #CommandProc callback type. The boolean parameter indicates if the + * command succeeded or failed. + * + * @param result The result of the executed command + * @param tile The tile of the command action + * @param p1 Additional data of the command + * @param p1 Additional data of the command + * @see CommandProc + */ +typedef void CommandCallback(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2); + +/** + * Structure for buffering the build command when selecting a station to join. + */ +struct CommandContainer { + TileIndex tile; ///< tile command being executed on. + uint32 p1; ///< parameter p1. + uint32 p2; ///< parameter p2. + uint32 cmd; ///< command being executed. + CommandCallback *callback; ///< any callback function executed upon successful completion of the command. + char text[32 * MAX_CHAR_LENGTH]; ///< possible text sent for name changes etc, in bytes including '\0'. +}; + +#endif /* COMMAND_TYPE_H */ diff --git a/src/company_base.h b/src/company_base.h new file mode 100644 index 0000000..6385d60 --- /dev/null +++ b/src/company_base.h @@ -0,0 +1,173 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file company_base.h Definition of stuff that is very close to a company, like the company struct itself. */ + +#ifndef COMPANY_BASE_H +#define COMPANY_BASE_H + +#include "road_type.h" +#include "livery.h" +#include "autoreplace_type.h" +#include "tile_type.h" +#include "settings_type.h" +#include "group.h" + +/** Statistics about the economy. */ +struct CompanyEconomyEntry { + Money income; ///< The amount of income. + Money expenses; ///< The amount of expenses. + CargoArray delivered_cargo; ///< The amount of delivered cargo. + int32 performance_history; ///< Company score (scale 0-1000) + Money company_value; ///< The value of the company. +}; + +struct CompanyInfrastructure { + uint32 road[ROADTYPE_END]; ///< Count of company owned track bits for each road type. + uint32 signal; ///< Count of company owned signals. + uint32 rail[RAILTYPE_END]; ///< Count of company owned track bits for each rail type. + uint32 water; ///< Count of company owned track bits for canals. + uint32 station; ///< Count of company owned station tiles. + uint32 airport; ///< Count of company owned airports. + + /** Get total sum of all owned track bits. */ + uint32 GetRailTotal() const + { + uint32 total = 0; + for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) total += this->rail[rt]; + return total; + } +}; + +typedef Pool CompanyPool; +extern CompanyPool _company_pool; + + +/** Statically loadable part of Company pool item */ +struct CompanyProperties { + uint32 name_2; ///< Parameter of #name_1. + uint16 name_1; ///< Name of the company if the user did not change it. + char *name; ///< Name of the company if the user changed it. + + uint16 president_name_1; ///< Name of the president if the user did not change it. + uint32 president_name_2; ///< Parameter of #president_name_1 + char *president_name; ///< Name of the president if the user changed it. + + CompanyManagerFace face; ///< Face description of the president. + + Money money; ///< Money owned by the company. + byte money_fraction; ///< Fraction of money of the company, too small to represent in #money. + Money current_loan; ///< Amount of money borrowed from the bank. + + byte colour; ///< Company colour. + + RailTypes avail_railtypes; ///< Rail types available to the company. + + byte block_preview; ///< Number of quarters that the company is not allowed to get new exclusive engine previews (see CompaniesGenStatistics). + + TileIndex location_of_HQ; ///< Northern tile of HQ; #INVALID_TILE when there is none. + TileIndex last_build_coordinate; ///< Coordinate of the last build thing by this company. + + OwnerByte share_owners[4]; ///< Owners of the 4 shares of the company. #INVALID_OWNER if nobody has bought them yet. + + Year inaugurated_year; ///< Year of starting the company. + + byte months_of_bankruptcy; ///< Number of months that the company is unable to pay its debts + CompanyMask bankrupt_asked; ///< which companies were asked about buying it? + int16 bankrupt_timeout; ///< If bigger than \c 0, amount of time to wait for an answer on an offer to buy this company. + Money bankrupt_value; + + uint32 terraform_limit; ///< Amount of tileheights we can (still) terraform (times 65536). + uint32 clear_limit; ///< Amount of tiles we can (still) clear (times 65536). + uint32 tree_limit; ///< Amount of trees we can (still) plant (times 65536). + + /** + * If \c true, the company is (also) controlled by the computer (a NoAI program). + * @note It is possible that the user is also participating in such a company. + */ + bool is_ai; + + Money yearly_expenses[3][EXPENSES_END]; ///< Expenses of the company for the last three years, in every #Expenses category. + CompanyEconomyEntry cur_economy; ///< Economic data of the company of this quarter. + CompanyEconomyEntry old_economy[MAX_HISTORY_QUARTERS]; ///< Economic data of the company of the last #MAX_HISTORY_QUARTERS quarters. + byte num_valid_stat_ent; ///< Number of valid statistical entries in #old_economy. + + CompanyProperties() : name(NULL), president_name(NULL) {} + + ~CompanyProperties() + { + free(this->name); + free(this->president_name); + } +}; + +struct Company : CompanyPool::PoolItem<&_company_pool>, CompanyProperties { + Company(uint16 name_1 = 0, bool is_ai = false); + ~Company(); + + Livery livery[LS_END]; + RoadTypes avail_roadtypes; ///< Road types available to this company. + + class AIInstance *ai_instance; + class AIInfo *ai_info; + + EngineRenewList engine_renew_list; ///< Engine renewals of this company. + CompanySettings settings; ///< settings specific for each company + GroupStatistics group_all[VEH_COMPANY_END]; ///< NOSAVE: Statistics for the ALL_GROUP group. + GroupStatistics group_default[VEH_COMPANY_END]; ///< NOSAVE: Statistics for the DEFAULT_GROUP group. + + CompanyInfrastructure infrastructure; ///< NOSAVE: Counts of company owned infrastructure. + + /** + * Is this company a valid company, controlled by the computer (a NoAI program)? + * @param index Index in the pool. + * @return \c true if it is a valid, computer controlled company, else \c false. + */ + static inline bool IsValidAiID(size_t index) + { + const Company *c = Company::GetIfValid(index); + return c != NULL && c->is_ai; + } + + /** + * Is this company a valid company, not controlled by a NoAI program? + * @param index Index in the pool. + * @return \c true if it is a valid, human controlled company, else \c false. + * @note If you know that \a index refers to a valid company, you can use #IsHumanID() instead. + */ + static inline bool IsValidHumanID(size_t index) + { + const Company *c = Company::GetIfValid(index); + return c != NULL && !c->is_ai; + } + + /** + * Is this company a company not controlled by a NoAI program? + * @param index Index in the pool. + * @return \c true if it is a human controlled company, else \c false. + * @pre \a index must be a valid CompanyID. + * @note If you don't know whether \a index refers to a valid company, you should use #IsValidHumanID() instead. + */ + static inline bool IsHumanID(size_t index) + { + return !Company::Get(index)->is_ai; + } + + static void PostDestructor(size_t index); +}; + +#define FOR_ALL_COMPANIES_FROM(var, start) FOR_ALL_ITEMS_FROM(Company, company_index, var, start) +#define FOR_ALL_COMPANIES(var) FOR_ALL_COMPANIES_FROM(var, 0) + +Money CalculateCompanyValue(const Company *c, bool including_loan = true); + +extern uint _next_competitor_start; +extern uint _cur_company_tick_index; + +#endif /* COMPANY_BASE_H */ diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp new file mode 100644 index 0000000..a2b7f73 --- /dev/null +++ b/src/company_cmd.cpp @@ -0,0 +1,1170 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file company_cmd.cpp Handling of companies. */ + +#include "stdafx.h" +#include "company_base.h" +#include "company_func.h" +#include "company_gui.h" +#include "town.h" +#include "news_func.h" +#include "cmd_helper.h" +#include "command_func.h" +#include "network/network.h" +#include "network/network_func.h" +#include "network/network_base.h" +#include "network/network_admin.h" +#include "ai/ai.hpp" +#include "company_manager_face.h" +#include "window_func.h" +#include "strings_func.h" +#include "date_func.h" +#include "sound_func.h" +#include "rail.h" +#include "core/pool_func.hpp" +#include "settings_func.h" +#include "vehicle_base.h" +#include "vehicle_func.h" +#include "smallmap_gui.h" +#include "game/game.hpp" +#include "goal_base.h" +#include "story_base.h" + +#include "table/strings.h" + +#include "safeguards.h" + +void ClearEnginesHiddenFlagOfCompany(CompanyID cid); + +CompanyByte _local_company; ///< Company controlled by the human player at this client. Can also be #COMPANY_SPECTATOR. +CompanyByte _current_company; ///< Company currently doing an action. +Colours _company_colours[MAX_COMPANIES]; ///< NOSAVE: can be determined from company structs. +CompanyManagerFace _company_manager_face; ///< for company manager face storage in openttd.cfg +uint _next_competitor_start; ///< the number of ticks before the next AI is started +uint _cur_company_tick_index; ///< used to generate a name for one company that doesn't have a name yet per tick + +CompanyPool _company_pool("Company"); ///< Pool of companies. +INSTANTIATE_POOL_METHODS(Company) + +/** + * Constructor. + * @param name_1 Name of the company. + * @param is_ai A computer program is running for this company. + */ +Company::Company(uint16 name_1, bool is_ai) +{ + this->name_1 = name_1; + this->location_of_HQ = INVALID_TILE; + this->is_ai = is_ai; + this->terraform_limit = _settings_game.construction.terraform_frame_burst << 16; + this->clear_limit = _settings_game.construction.clear_frame_burst << 16; + this->tree_limit = _settings_game.construction.tree_frame_burst << 16; + + for (uint j = 0; j < 4; j++) this->share_owners[j] = COMPANY_SPECTATOR; + InvalidateWindowData(WC_PERFORMANCE_DETAIL, 0, INVALID_COMPANY); + InvalidateWindowClassesData(WC_WATCH_COMPANY, 0); +} + +/** Destructor. */ +Company::~Company() +{ + if (CleaningPool()) return; + + DeleteCompanyWindows(this->index); +} + +/** + * Invalidating some stuff after removing item from the pool. + * @param index index of deleted item + */ +void Company::PostDestructor(size_t index) +{ + InvalidateWindowData(WC_GRAPH_LEGEND, 0, (int)index); + InvalidateWindowData(WC_PERFORMANCE_DETAIL, 0, (int)index); + InvalidateWindowData(WC_COMPANY_LEAGUE, 0, 0); + InvalidateWindowData(WC_LINKGRAPH_LEGEND, 0); + /* If the currently shown error message has this company in it, then close it. */ + InvalidateWindowData(WC_ERRMSG, 0); + InvalidateWindowClassesData(WC_WATCH_COMPANY, 0); +} + +/** + * Sets the local company and updates the settings that are set on a + * per-company basis to reflect the core's state in the GUI. + * @param new_company the new company + * @pre Company::IsValidID(new_company) || new_company == COMPANY_SPECTATOR || new_company == OWNER_NONE + */ +void SetLocalCompany(CompanyID new_company) +{ + /* company could also be COMPANY_SPECTATOR or OWNER_NONE */ + assert(Company::IsValidID(new_company) || new_company == COMPANY_SPECTATOR || new_company == OWNER_NONE); + +#ifdef ENABLE_NETWORK + /* Delete the chat window, if you were team chatting. */ + InvalidateWindowData(WC_SEND_NETWORK_MSG, DESTTYPE_TEAM, _local_company); +#endif + + assert(IsLocalCompany()); + + _current_company = _local_company = new_company; + + /* Delete any construction windows... */ + DeleteConstructionWindows(); + + /* ... and redraw the whole screen. */ + MarkWholeScreenDirty(); + InvalidateWindowClassesData(WC_SIGN_LIST, -1); +} + +/** + * Get the colour for DrawString-subroutines which matches the colour of the company. + * @param company Company to get the colour of. + * @return Colour of \a company. + */ +TextColour GetDrawStringCompanyColour(CompanyID company) +{ + if (!Company::IsValidID(company)) return (TextColour)_colour_gradient[COLOUR_WHITE][4] | TC_IS_PALETTE_COLOUR; + return (TextColour)_colour_gradient[_company_colours[company]][4] | TC_IS_PALETTE_COLOUR; +} + +/** + * Draw the icon of a company. + * @param c Company that needs its icon drawn. + * @param x Horizontal coordinate of the icon. + * @param y Vertical coordinate of the icon. + */ +void DrawCompanyIcon(CompanyID c, int x, int y) +{ + DrawSprite(SPR_COMPANY_ICON, COMPANY_SPRITE_COLOUR(c), x, y); +} + +/** + * Checks whether a company manager's face is a valid encoding. + * Unused bits are not enforced to be 0. + * @param cmf the fact to check + * @return true if and only if the face is valid + */ +static bool IsValidCompanyManagerFace(CompanyManagerFace cmf) +{ + if (!AreCompanyManagerFaceBitsValid(cmf, CMFV_GEN_ETHN, GE_WM)) return false; + + GenderEthnicity ge = (GenderEthnicity)GetCompanyManagerFaceBits(cmf, CMFV_GEN_ETHN, GE_WM); + bool has_moustache = !HasBit(ge, GENDER_FEMALE) && GetCompanyManagerFaceBits(cmf, CMFV_HAS_MOUSTACHE, ge) != 0; + bool has_tie_earring = !HasBit(ge, GENDER_FEMALE) || GetCompanyManagerFaceBits(cmf, CMFV_HAS_TIE_EARRING, ge) != 0; + bool has_glasses = GetCompanyManagerFaceBits(cmf, CMFV_HAS_GLASSES, ge) != 0; + + if (!AreCompanyManagerFaceBitsValid(cmf, CMFV_EYE_COLOUR, ge)) return false; + for (CompanyManagerFaceVariable cmfv = CMFV_CHEEKS; cmfv < CMFV_END; cmfv++) { + switch (cmfv) { + case CMFV_MOUSTACHE: if (!has_moustache) continue; break; + case CMFV_LIPS: // FALL THROUGH + case CMFV_NOSE: if (has_moustache) continue; break; + case CMFV_TIE_EARRING: if (!has_tie_earring) continue; break; + case CMFV_GLASSES: if (!has_glasses) continue; break; + default: break; + } + if (!AreCompanyManagerFaceBitsValid(cmf, cmfv, ge)) return false; + } + + return true; +} + +/** + * Refresh all windows owned by a company. + * @param company Company that changed, and needs its windows refreshed. + */ +void InvalidateCompanyWindows(const Company *company) +{ + CompanyID cid = company->index; + + if (cid == _local_company) SetWindowDirty(WC_STATUS_BAR, 0); + SetWindowDirty(WC_FINANCES, cid); +} + +/** + * Verify whether the company can pay the bill. + * @param cost [inout] Money to pay, is changed to an error if the company does not have enough money. + * @return Function returns \c true if the company has enough money, else it returns \c false. + */ +bool CheckCompanyHasMoney(CommandCost &cost) +{ + if (cost.GetCost() > 0) { + const Company *c = Company::GetIfValid(_current_company); + if (c != NULL && cost.GetCost() > c->money) { + SetDParam(0, cost.GetCost()); + cost.MakeError(STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY); + return false; + } + } + return true; +} + +/** + * Deduct costs of a command from the money of a company. + * @param c Company to pay the bill. + * @param cost Money to pay. + */ +static void SubtractMoneyFromAnyCompany(Company *c, CommandCost cost) +{ + if (cost.GetCost() == 0) return; + assert(cost.GetExpensesType() != INVALID_EXPENSES); + + c->money -= cost.GetCost(); + c->yearly_expenses[0][cost.GetExpensesType()] += cost.GetCost(); + + if (HasBit(1 << EXPENSES_TRAIN_INC | + 1 << EXPENSES_ROADVEH_INC | + 1 << EXPENSES_AIRCRAFT_INC | + 1 << EXPENSES_SHIP_INC | + 1 << EXPENSES_SHARING_INC, cost.GetExpensesType())) { + c->cur_economy.income -= cost.GetCost(); + } else if (HasBit(1 << EXPENSES_TRAIN_RUN | + 1 << EXPENSES_ROADVEH_RUN | + 1 << EXPENSES_AIRCRAFT_RUN | + 1 << EXPENSES_SHIP_RUN | + 1 << EXPENSES_PROPERTY | + 1 << EXPENSES_LOAN_INT | + 1 << EXPENSES_SHARING_COST, cost.GetExpensesType())) { + c->cur_economy.expenses -= cost.GetCost(); + } + + InvalidateCompanyWindows(c); +} + +/** + * Subtract money from the #_current_company, if the company is valid. + * @param cost Money to pay. + */ +void SubtractMoneyFromCompany(CommandCost cost) +{ + Company *c = Company::GetIfValid(_current_company); + if (c != NULL) SubtractMoneyFromAnyCompany(c, cost); +} + +/** + * Subtract money from a company, including the money fraction. + * @param company Company paying the bill. + * @param cst Cost of a command. + */ +void SubtractMoneyFromCompanyFract(CompanyID company, CommandCost cst) +{ + Company *c = Company::Get(company); + byte m = c->money_fraction; + Money cost = cst.GetCost(); + + c->money_fraction = m - (byte)cost; + cost >>= 8; + if (c->money_fraction > m) cost++; + if (cost != 0) SubtractMoneyFromAnyCompany(c, CommandCost(cst.GetExpensesType(), cost)); +} + +/** Update the landscaping limits per company. */ +void UpdateLandscapingLimits() +{ + Company *c; + FOR_ALL_COMPANIES(c) { + c->terraform_limit = min(c->terraform_limit + _settings_game.construction.terraform_per_64k_frames, (uint32)_settings_game.construction.terraform_frame_burst << 16); + c->clear_limit = min(c->clear_limit + _settings_game.construction.clear_per_64k_frames, (uint32)_settings_game.construction.clear_frame_burst << 16); + c->tree_limit = min(c->tree_limit + _settings_game.construction.tree_per_64k_frames, (uint32)_settings_game.construction.tree_frame_burst << 16); + } +} + +/** + * Set the right DParams to get the name of an owner. + * @param owner the owner to get the name of. + * @param tile optional tile to get the right town. + * @pre if tile == 0, then owner can't be OWNER_TOWN. + */ +void GetNameOfOwner(Owner owner, TileIndex tile) +{ + SetDParam(2, owner); + + if (owner != OWNER_TOWN) { + if (!Company::IsValidID(owner)) { + SetDParam(0, STR_COMPANY_SOMEONE); + } else { + SetDParam(0, STR_COMPANY_NAME); + SetDParam(1, owner); + } + } else { + assert(tile != 0); + const Town *t = ClosestTownFromTile(tile, UINT_MAX); + + SetDParam(0, STR_TOWN_NAME); + SetDParam(1, t->index); + } +} + + +/** + * Check whether the current owner owns something. + * If that isn't the case an appropriate error will be given. + * @param owner the owner of the thing to check. + * @param tile optional tile to get the right town. + * @pre if tile == 0 then the owner can't be OWNER_TOWN. + * @return A succeeded command iff it's owned by the current company, else a failed command. + */ +CommandCost CheckOwnership(Owner owner, TileIndex tile) +{ + assert(owner < OWNER_END); + assert(owner != OWNER_TOWN || tile != 0); + + if (owner == _current_company) return CommandCost(); + + GetNameOfOwner(owner, tile); + return_cmd_error(STR_ERROR_OWNED_BY); +} + +/** + * Check whether the current owner owns the stuff on + * the given tile. If that isn't the case an + * appropriate error will be given. + * @param tile the tile to check. + * @return A succeeded command iff it's owned by the current company, else a failed command. + */ +CommandCost CheckTileOwnership(TileIndex tile) +{ + Owner owner = GetTileOwner(tile); + + assert(owner < OWNER_END); + + if (owner == _current_company) return CommandCost(); + + /* no need to get the name of the owner unless we're the local company (saves some time) */ + if (IsLocalCompany()) GetNameOfOwner(owner, tile); + return_cmd_error(STR_ERROR_OWNED_BY); +} + +/** + * Generate the name of a company from the last build coordinate. + * @param c Company to give a name. + */ +static void GenerateCompanyName(Company *c) +{ + /* Reserve space for extra unicode character. We need to do this to be able + * to detect too long company name. */ + char buffer[(MAX_LENGTH_COMPANY_NAME_CHARS + 1) * MAX_CHAR_LENGTH]; + + if (c->name_1 != STR_SV_UNNAMED) return; + if (c->last_build_coordinate == 0) return; + + Town *t = ClosestTownFromTile(c->last_build_coordinate, UINT_MAX); + + StringID str; + uint32 strp; + if (t->name == NULL && IsInsideMM(t->townnametype, SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_LAST + 1)) { + str = t->townnametype - SPECSTR_TOWNNAME_START + SPECSTR_COMPANY_NAME_START; + strp = t->townnameparts; + +verify_name:; + /* No companies must have this name already */ + Company *cc; + FOR_ALL_COMPANIES(cc) { + if (cc->name_1 == str && cc->name_2 == strp) goto bad_town_name; + } + + GetString(buffer, str, lastof(buffer)); + if (Utf8StringLength(buffer) >= MAX_LENGTH_COMPANY_NAME_CHARS) goto bad_town_name; + +set_name:; + c->name_1 = str; + c->name_2 = strp; + + MarkWholeScreenDirty(); + + if (c->is_ai) { + CompanyNewsInformation *cni = MallocT(1); + cni->FillData(c); + SetDParam(0, STR_NEWS_COMPANY_LAUNCH_TITLE); + SetDParam(1, STR_NEWS_COMPANY_LAUNCH_DESCRIPTION); + SetDParamStr(2, cni->company_name); + SetDParam(3, t->index); + AddNewsItem(STR_MESSAGE_NEWS_FORMAT, NT_COMPANY_INFO, NF_COMPANY, NR_TILE, c->last_build_coordinate, NR_NONE, UINT32_MAX, cni); + } + return; + } +bad_town_name:; + + if (c->president_name_1 == SPECSTR_PRESIDENT_NAME) { + str = SPECSTR_ANDCO_NAME; + strp = c->president_name_2; + goto set_name; + } else { + str = SPECSTR_ANDCO_NAME; + strp = Random(); + goto verify_name; + } +} + +/** Sorting weights for the company colours. */ +static const byte _colour_sort[COLOUR_END] = {2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 2, 2, 3, 1, 1, 1}; +/** Similar colours, so we can try to prevent same coloured companies. */ +static const Colours _similar_colour[COLOUR_END][2] = { + { COLOUR_BLUE, COLOUR_LIGHT_BLUE }, // COLOUR_DARK_BLUE + { COLOUR_GREEN, COLOUR_DARK_GREEN }, // COLOUR_PALE_GREEN + { INVALID_COLOUR, INVALID_COLOUR }, // COLOUR_PINK + { COLOUR_ORANGE, INVALID_COLOUR }, // COLOUR_YELLOW + { INVALID_COLOUR, INVALID_COLOUR }, // COLOUR_RED + { COLOUR_DARK_BLUE, COLOUR_BLUE }, // COLOUR_LIGHT_BLUE + { COLOUR_PALE_GREEN, COLOUR_DARK_GREEN }, // COLOUR_GREEN + { COLOUR_PALE_GREEN, COLOUR_GREEN }, // COLOUR_DARK_GREEN + { COLOUR_DARK_BLUE, COLOUR_LIGHT_BLUE }, // COLOUR_BLUE + { COLOUR_BROWN, COLOUR_ORANGE }, // COLOUR_CREAM + { COLOUR_PURPLE, INVALID_COLOUR }, // COLOUR_MAUVE + { COLOUR_MAUVE, INVALID_COLOUR }, // COLOUR_PURPLE + { COLOUR_YELLOW, COLOUR_CREAM }, // COLOUR_ORANGE + { COLOUR_CREAM, INVALID_COLOUR }, // COLOUR_BROWN + { COLOUR_WHITE, INVALID_COLOUR }, // COLOUR_GREY + { COLOUR_GREY, INVALID_COLOUR }, // COLOUR_WHITE +}; + +/** + * Generate a company colour. + * @return Generated company colour. + */ +static Colours GenerateCompanyColour() +{ + Colours colours[COLOUR_END]; + + /* Initialize array */ + for (uint i = 0; i < COLOUR_END; i++) colours[i] = (Colours)i; + + /* And randomize it */ + for (uint i = 0; i < 100; i++) { + uint r = Random(); + Swap(colours[GB(r, 0, 4)], colours[GB(r, 4, 4)]); + } + + /* Bubble sort it according to the values in table 1 */ + for (uint i = 0; i < COLOUR_END; i++) { + for (uint j = 1; j < COLOUR_END; j++) { + if (_colour_sort[colours[j - 1]] < _colour_sort[colours[j]]) { + Swap(colours[j - 1], colours[j]); + } + } + } + + /* Move the colours that look similar to each company's colour to the side */ + Company *c; + FOR_ALL_COMPANIES(c) { + Colours pcolour = (Colours)c->colour; + + for (uint i = 0; i < COLOUR_END; i++) { + if (colours[i] == pcolour) { + colours[i] = INVALID_COLOUR; + break; + } + } + + for (uint j = 0; j < 2; j++) { + Colours similar = _similar_colour[pcolour][j]; + if (similar == INVALID_COLOUR) break; + + for (uint i = 1; i < COLOUR_END; i++) { + if (colours[i - 1] == similar) Swap(colours[i - 1], colours[i]); + } + } + } + + /* Return the first available colour */ + for (uint i = 0; i < COLOUR_END; i++) { + if (colours[i] != INVALID_COLOUR) return colours[i]; + } + + NOT_REACHED(); +} + +/** + * Generate a random president name of a company. + * @param c Company that needs a new president name. + */ +static void GeneratePresidentName(Company *c) +{ + for (;;) { +restart:; + c->president_name_2 = Random(); + c->president_name_1 = SPECSTR_PRESIDENT_NAME; + + /* Reserve space for extra unicode character. We need to do this to be able + * to detect too long president name. */ + char buffer[(MAX_LENGTH_PRESIDENT_NAME_CHARS + 1) * MAX_CHAR_LENGTH]; + SetDParam(0, c->index); + GetString(buffer, STR_PRESIDENT_NAME, lastof(buffer)); + if (Utf8StringLength(buffer) >= MAX_LENGTH_PRESIDENT_NAME_CHARS) continue; + + Company *cc; + FOR_ALL_COMPANIES(cc) { + if (c != cc) { + /* Reserve extra space so even overlength president names can be compared. */ + char buffer2[(MAX_LENGTH_PRESIDENT_NAME_CHARS + 1) * MAX_CHAR_LENGTH]; + SetDParam(0, cc->index); + GetString(buffer2, STR_PRESIDENT_NAME, lastof(buffer2)); + if (strcmp(buffer2, buffer) == 0) goto restart; + } + } + return; + } +} + +/** + * Reset the livery schemes to the company's primary colour. + * This is used on loading games without livery information and on new company start up. + * @param c Company to reset. + */ +void ResetCompanyLivery(Company *c) +{ + for (LiveryScheme scheme = LS_BEGIN; scheme < LS_END; scheme++) { + c->livery[scheme].in_use = false; + c->livery[scheme].colour1 = c->colour; + c->livery[scheme].colour2 = c->colour; + } +} + +/** + * Create a new company and sets all company variables default values + * + * @param is_ai is an AI company? + * @param company CompanyID to use for the new company + * @return the company struct + */ +Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY) +{ + if (!Company::CanAllocateItem()) return NULL; + + /* we have to generate colour before this company is valid */ + Colours colour = GenerateCompanyColour(); + + Company *c; + if (company == INVALID_COMPANY) { + c = new Company(STR_SV_UNNAMED, is_ai); + } else { + if (Company::IsValidID(company)) return NULL; + c = new (company) Company(STR_SV_UNNAMED, is_ai); + } + + c->colour = colour; + + ResetCompanyLivery(c); + _company_colours[c->index] = (Colours)c->colour; + + c->money = c->current_loan = (100000ll * _economy.inflation_prices >> 16) / 50000 * 50000; + + c->share_owners[0] = c->share_owners[1] = c->share_owners[2] = c->share_owners[3] = INVALID_OWNER; + + c->avail_railtypes = GetCompanyRailtypes(c->index); + c->avail_roadtypes = GetCompanyRoadtypes(c->index); + c->inaugurated_year = _cur_year; + RandomCompanyManagerFaceBits(c->face, (GenderEthnicity)Random(), false, false); // create a random company manager face + + SetDefaultCompanySettings(c->index); + ClearEnginesHiddenFlagOfCompany(c->index); + + GeneratePresidentName(c); + + SetWindowDirty(WC_GRAPH_LEGEND, 0); + SetWindowClassesDirty(WC_CLIENT_LIST_POPUP); + SetWindowDirty(WC_CLIENT_LIST, 0); + InvalidateWindowData(WC_LINKGRAPH_LEGEND, 0); + BuildOwnerLegend(); + InvalidateWindowData(WC_SMALLMAP, 0, 1); + + if (is_ai && (!_networking || _network_server)) AI::StartNew(c->index); + + AI::BroadcastNewEvent(new ScriptEventCompanyNew(c->index), c->index); + Game::NewEvent(new ScriptEventCompanyNew(c->index)); + + if (!is_ai) UpdateAllTownVirtCoords(); + + return c; +} + +/** Start the next competitor now. */ +void StartupCompanies() +{ + _next_competitor_start = 0; +} + +/** Start a new competitor company if possible. */ +static void MaybeStartNewCompany() +{ +#ifdef ENABLE_NETWORK + if (_networking && Company::GetNumItems() >= _settings_client.network.max_companies) return; +#endif /* ENABLE_NETWORK */ + + Company *c; + + /* count number of competitors */ + uint n = 0; + FOR_ALL_COMPANIES(c) { + if (c->is_ai) n++; + } + + if (n < (uint)_settings_game.difficulty.max_no_competitors) { + /* Send a command to all clients to start up a new AI. + * Works fine for Multiplayer and Singleplayer */ + DoCommandP(0, 1 | INVALID_COMPANY << 16, 0, CMD_COMPANY_CTRL); + } +} + +/** Initialize the pool of companies. */ +void InitializeCompanies() +{ + _cur_company_tick_index = 0; +} + +/** + * May company \a cbig buy company \a csmall? + * @param cbig Company buying \a csmall. + * @param csmall Company getting bought. + * @return Return \c true if it is allowed. + */ +bool MayCompanyTakeOver(CompanyID cbig, CompanyID csmall) +{ + const Company *c1 = Company::Get(cbig); + const Company *c2 = Company::Get(csmall); + + /* Do the combined vehicle counts stay within the limits? */ + return c1->group_all[VEH_TRAIN].num_vehicle + c2->group_all[VEH_TRAIN].num_vehicle <= _settings_game.vehicle.max_trains && + c1->group_all[VEH_ROAD].num_vehicle + c2->group_all[VEH_ROAD].num_vehicle <= _settings_game.vehicle.max_roadveh && + c1->group_all[VEH_SHIP].num_vehicle + c2->group_all[VEH_SHIP].num_vehicle <= _settings_game.vehicle.max_ships && + c1->group_all[VEH_AIRCRAFT].num_vehicle + c2->group_all[VEH_AIRCRAFT].num_vehicle <= _settings_game.vehicle.max_aircraft; +} + +/** + * Handle the bankruptcy take over of a company. + * Companies going bankrupt will ask the other companies in order of their + * performance rating, so better performing companies get the 'do you want to + * merge with Y' question earlier. The question will then stay till either the + * company has gone bankrupt or got merged with a company. + * + * @param c the company that is going bankrupt. + */ +static void HandleBankruptcyTakeover(Company *c) +{ + /* Amount of time out for each company to take over a company; + * Timeout is a quarter (3 months of 30 days) divided over the + * number of companies. The minimum number of days in a quarter + * is 90: 31 in January, 28 in February and 31 in March. + * Note that the company going bankrupt can't buy itself. */ + static const int TAKE_OVER_TIMEOUT = 3 * 30 * DAY_TICKS / (MAX_COMPANIES - 1); + + assert(c->bankrupt_asked != 0); + + /* We're currently asking some company to buy 'us' */ + if (c->bankrupt_timeout != 0) { + c->bankrupt_timeout -= MAX_COMPANIES; + if (c->bankrupt_timeout > 0) return; + c->bankrupt_timeout = 0; + + return; + } + + /* Did we ask everyone for bankruptcy? If so, bail out. */ + if (c->bankrupt_asked == MAX_UVALUE(CompanyMask)) return; + + Company *c2, *best = NULL; + int32 best_performance = -1; + + /* Ask the company with the highest performance history first */ + FOR_ALL_COMPANIES(c2) { + if (c2->bankrupt_asked == 0 && // Don't ask companies going bankrupt themselves + !HasBit(c->bankrupt_asked, c2->index) && + best_performance < c2->old_economy[1].performance_history && + MayCompanyTakeOver(c2->index, c->index)) { + best_performance = c2->old_economy[1].performance_history; + best = c2; + } + } + + /* Asked all companies? */ + if (best_performance == -1) { + c->bankrupt_asked = MAX_UVALUE(CompanyMask); + return; + } + + SetBit(c->bankrupt_asked, best->index); + + c->bankrupt_timeout = TAKE_OVER_TIMEOUT; + if (best->is_ai) { + AI::NewEvent(best->index, new ScriptEventCompanyAskMerger(c->index, ClampToI32(c->bankrupt_value))); + } else if (IsInteractiveCompany(best->index)) { + ShowBuyCompanyDialog(c->index); + } +} + +/** Called every tick for updating some company info. */ +void OnTick_Companies() +{ + if (_game_mode == GM_EDITOR) return; + + Company *c = Company::GetIfValid(_cur_company_tick_index); + if (c != NULL) { + if (c->name_1 != 0) GenerateCompanyName(c); + if (c->bankrupt_asked != 0) HandleBankruptcyTakeover(c); + } + + if (_next_competitor_start == 0) { + _next_competitor_start = AI::GetStartNextTime() * DAY_TICKS; + } + + if (AI::CanStartNew() && _game_mode != GM_MENU && --_next_competitor_start == 0) { + MaybeStartNewCompany(); + } + + _cur_company_tick_index = (_cur_company_tick_index + 1) % MAX_COMPANIES; +} + +/** + * A year has passed, update the economic data of all companies, and perhaps show the + * financial overview window of the local company. + */ +void CompaniesYearlyLoop() +{ + Company *c; + + /* Copy statistics */ + FOR_ALL_COMPANIES(c) { + memmove(&c->yearly_expenses[1], &c->yearly_expenses[0], sizeof(c->yearly_expenses) - sizeof(c->yearly_expenses[0])); + memset(&c->yearly_expenses[0], 0, sizeof(c->yearly_expenses[0])); + SetWindowDirty(WC_FINANCES, c->index); + } + + if (_settings_client.gui.show_finances && _local_company != COMPANY_SPECTATOR) { + ShowCompanyFinances(_local_company); + c = Company::Get(_local_company); + if (c->num_valid_stat_ent > 5 && c->old_economy[0].performance_history < c->old_economy[4].performance_history) { + if (_settings_client.sound.new_year) SndPlayFx(SND_01_BAD_YEAR); + } else { + if (_settings_client.sound.new_year) SndPlayFx(SND_00_GOOD_YEAR); + } + } +} + +/** + * Fill the CompanyNewsInformation struct with the required data. + * @param c the current company. + * @param other the other company (use \c NULL if not relevant). + */ +void CompanyNewsInformation::FillData(const Company *c, const Company *other) +{ + SetDParam(0, c->index); + GetString(this->company_name, STR_COMPANY_NAME, lastof(this->company_name)); + + if (other == NULL) { + *this->other_company_name = '\0'; + } else { + SetDParam(0, other->index); + GetString(this->other_company_name, STR_COMPANY_NAME, lastof(this->other_company_name)); + c = other; + } + + SetDParam(0, c->index); + GetString(this->president_name, STR_PRESIDENT_NAME_MANAGER, lastof(this->president_name)); + + this->colour = c->colour; + this->face = c->face; + +} + +/** + * Called whenever company related information changes in order to notify admins. + * @param company The company data changed of. + */ +void CompanyAdminUpdate(const Company *company) +{ +#ifdef ENABLE_NETWORK + if (_network_server) NetworkAdminCompanyUpdate(company); +#endif /* ENABLE_NETWORK */ +} + +/** + * Called whenever a company is removed in order to notify admins. + * @param company_id The company that was removed. + * @param reason The reason the company was removed. + */ +void CompanyAdminRemove(CompanyID company_id, CompanyRemoveReason reason) +{ +#ifdef ENABLE_NETWORK + if (_network_server) NetworkAdminCompanyRemove(company_id, (AdminCompanyRemoveReason)reason); +#endif /* ENABLE_NETWORK */ +} + +/** + * Control the companies: add, delete, etc. + * @param tile unused + * @param flags operation to perform + * @param p1 various functionality + * - bits 0..15: + * = 0 - create a new company + * = 1 - create a new AI company + * = 2 - delete a company + * - bits 16..24: CompanyID + * @param p2 ClientID + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + InvalidateWindowData(WC_COMPANY_LEAGUE, 0, 0); + CompanyID company_id = (CompanyID)GB(p1, 16, 8); +#ifdef ENABLE_NETWORK + ClientID client_id = (ClientID)p2; +#endif /* ENABLE_NETWORK */ + + switch (GB(p1, 0, 16)) { + case 0: { // Create a new company + /* This command is only executed in a multiplayer game */ + if (!_networking) return CMD_ERROR; + +#ifdef ENABLE_NETWORK + /* Has the network client a correct ClientIndex? */ + if (!(flags & DC_EXEC)) return CommandCost(); + NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id); +#ifndef DEBUG_DUMP_COMMANDS + /* When replaying the client ID is not a valid client; there + * are actually no clients at all. However, the company has to + * be created, otherwise we cannot rerun the game properly. + * So only allow a NULL client info in that case. */ + if (ci == NULL) return CommandCost(); +#endif /* NOT DEBUG_DUMP_COMMANDS */ + + /* Delete multiplayer progress bar */ + DeleteWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); + + Company *c = DoStartupNewCompany(false); + + /* A new company could not be created, revert to being a spectator */ + if (c == NULL) { + if (_network_server) { + ci->client_playas = COMPANY_SPECTATOR; + NetworkUpdateClientInfo(ci->client_id); + } + break; + } + + /* This is the client (or non-dedicated server) who wants a new company */ + if (client_id == _network_own_client_id) { + assert(_local_company == COMPANY_SPECTATOR); + SetLocalCompany(c->index); + if (!StrEmpty(_settings_client.network.default_company_pass)) { + NetworkChangeCompanyPassword(_local_company, _settings_client.network.default_company_pass); + } + + /* Now that we have a new company, broadcast our company settings to + * all clients so everything is in sync */ + SyncCompanySettings(); + + MarkWholeScreenDirty(); + } + + NetworkServerNewCompany(c, ci); +#endif /* ENABLE_NETWORK */ + break; + } + + case 1: { // Make a new AI company + if (!(flags & DC_EXEC)) return CommandCost(); + + if (company_id != INVALID_COMPANY && (company_id >= MAX_COMPANIES || Company::IsValidID(company_id))) return CMD_ERROR; + Company *c = DoStartupNewCompany(true, company_id); +#ifdef ENABLE_NETWORK + if (c != NULL) NetworkServerNewCompany(c, NULL); +#endif /* ENABLE_NETWORK */ + break; + } + + case 2: { // Delete a company + CompanyRemoveReason reason = (CompanyRemoveReason)GB(p2, 0, 2); + if (reason >= CRR_END) return CMD_ERROR; + + Company *c = Company::GetIfValid(company_id); + if (c == NULL) return CMD_ERROR; + + if (!(flags & DC_EXEC)) return CommandCost(); + + /* Delete any open window of the company */ + DeleteCompanyWindows(c->index); + CompanyNewsInformation *cni = MallocT(1); + cni->FillData(c); + + /* Show the bankrupt news */ + SetDParam(0, STR_NEWS_COMPANY_BANKRUPT_TITLE); + SetDParam(1, STR_NEWS_COMPANY_BANKRUPT_DESCRIPTION); + SetDParamStr(2, cni->company_name); + AddCompanyNewsItem(STR_MESSAGE_NEWS_FORMAT, cni); + + /* Remove the company */ + ChangeOwnershipOfCompanyItems(c->index, INVALID_OWNER); + if (c->is_ai) AI::Stop(c->index); + + CompanyID c_index = c->index; + delete c; + AI::BroadcastNewEvent(new ScriptEventCompanyBankrupt(c_index)); + Game::NewEvent(new ScriptEventCompanyBankrupt(c_index)); + CompanyAdminRemove(c_index, (CompanyRemoveReason)reason); + + if (StoryPage::GetNumItems() == 0 || Goal::GetNumItems() == 0) InvalidateWindowData(WC_MAIN_TOOLBAR, 0); + break; + } + + default: return CMD_ERROR; + } + + InvalidateWindowClassesData(WC_GAME_OPTIONS); + InvalidateWindowClassesData(WC_AI_SETTINGS); + InvalidateWindowClassesData(WC_AI_LIST); + + return CommandCost(); +} + +/** + * Change the company manager's face. + * @param tile unused + * @param flags operation to perform + * @param p1 unused + * @param p2 face bitmasked + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdSetCompanyManagerFace(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + CompanyManagerFace cmf = (CompanyManagerFace)p2; + + if (!IsValidCompanyManagerFace(cmf)) return CMD_ERROR; + + if (flags & DC_EXEC) { + Company::Get(_current_company)->face = cmf; + MarkWholeScreenDirty(); + } + return CommandCost(); +} + +/** + * Change the company's company-colour + * @param tile unused + * @param flags operation to perform + * @param p1 bitstuffed: + * p1 bits 0-7 scheme to set + * p1 bits 8-9 set in use state or first/second colour + * @param p2 new colour for vehicles, property, etc. + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdSetCompanyColour(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + Colours colour = Extract(p2); + LiveryScheme scheme = Extract(p1); + byte state = GB(p1, 8, 2); + + if (scheme >= LS_END || state >= 3 || colour == INVALID_COLOUR) return CMD_ERROR; + + Company *c = Company::Get(_current_company); + + /* Ensure no two companies have the same primary colour */ + if (scheme == LS_DEFAULT && state == 0) { + const Company *cc; + FOR_ALL_COMPANIES(cc) { + if (cc != c && cc->colour == colour) return CMD_ERROR; + } + } + + if (flags & DC_EXEC) { + switch (state) { + case 0: + c->livery[scheme].colour1 = colour; + + /* If setting the first colour of the default scheme, adjust the + * original and cached company colours too. */ + if (scheme == LS_DEFAULT) { + _company_colours[_current_company] = colour; + c->colour = colour; + CompanyAdminUpdate(c); + } + break; + + case 1: + c->livery[scheme].colour2 = colour; + break; + + case 2: + c->livery[scheme].in_use = colour != 0; + + /* Now handle setting the default scheme's in_use flag. + * This is different to the other schemes, as it signifies if any + * scheme is active at all. If this flag is not set, then no + * processing of vehicle types occurs at all, and only the default + * colours will be used. */ + + /* If enabling a scheme, set the default scheme to be in use too */ + if (colour != 0) { + c->livery[LS_DEFAULT].in_use = true; + break; + } + + /* Else loop through all schemes to see if any are left enabled. + * If not, disable the default scheme too. */ + c->livery[LS_DEFAULT].in_use = false; + for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) { + if (c->livery[scheme].in_use) { + c->livery[LS_DEFAULT].in_use = true; + break; + } + } + break; + + default: + break; + } + ResetVehicleColourMap(); + MarkWholeScreenDirty(); + + /* All graph related to companies use the company colour. */ + InvalidateWindowData(WC_INCOME_GRAPH, 0); + InvalidateWindowData(WC_OPERATING_PROFIT, 0); + InvalidateWindowData(WC_DELIVERED_CARGO, 0); + InvalidateWindowData(WC_PERFORMANCE_HISTORY, 0); + InvalidateWindowData(WC_COMPANY_VALUE, 0); + InvalidateWindowData(WC_LINKGRAPH_LEGEND, 0); + /* The smallmap owner view also stores the company colours. */ + BuildOwnerLegend(); + InvalidateWindowData(WC_SMALLMAP, 0, 1); + + /* Company colour data is indirectly cached. */ + Vehicle *v; + FOR_ALL_VEHICLES(v) { + if (v->owner == _current_company) v->InvalidateNewGRFCache(); + } + + extern void UpdateObjectColours(const Company *c); + UpdateObjectColours(c); + } + return CommandCost(); +} + +/** + * Is the given name in use as name of a company? + * @param name Name to search. + * @return \c true if the name us unique (that is, not in use), else \c false. + */ +static bool IsUniqueCompanyName(const char *name) +{ + const Company *c; + + FOR_ALL_COMPANIES(c) { + if (c->name != NULL && strcmp(c->name, name) == 0) return false; + } + + return true; +} + +/** + * Change the name of the company. + * @param tile unused + * @param flags operation to perform + * @param p1 unused + * @param p2 unused + * @param text the new name or an empty string when resetting to the default + * @return the cost of this operation or an error + */ +CommandCost CmdRenameCompany(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + bool reset = StrEmpty(text); + + if (!reset) { + if (Utf8StringLength(text) >= MAX_LENGTH_COMPANY_NAME_CHARS) return CMD_ERROR; + if (!IsUniqueCompanyName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE); + } + + if (flags & DC_EXEC) { + Company *c = Company::Get(_current_company); + free(c->name); + c->name = reset ? NULL : stredup(text); + MarkWholeScreenDirty(); + CompanyAdminUpdate(c); + } + + return CommandCost(); +} + +/** + * Is the given name in use as president name of a company? + * @param name Name to search. + * @return \c true if the name us unique (that is, not in use), else \c false. + */ +static bool IsUniquePresidentName(const char *name) +{ + const Company *c; + + FOR_ALL_COMPANIES(c) { + if (c->president_name != NULL && strcmp(c->president_name, name) == 0) return false; + } + + return true; +} + +/** + * Change the name of the president. + * @param tile unused + * @param flags operation to perform + * @param p1 unused + * @param p2 unused + * @param text the new name or an empty string when resetting to the default + * @return the cost of this operation or an error + */ +CommandCost CmdRenamePresident(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + bool reset = StrEmpty(text); + + if (!reset) { + if (Utf8StringLength(text) >= MAX_LENGTH_PRESIDENT_NAME_CHARS) return CMD_ERROR; + if (!IsUniquePresidentName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE); + } + + if (flags & DC_EXEC) { + Company *c = Company::Get(_current_company); + free(c->president_name); + + if (reset) { + c->president_name = NULL; + } else { + c->president_name = stredup(text); + + if (c->name_1 == STR_SV_UNNAMED && c->name == NULL) { + char buf[80]; + + seprintf(buf, lastof(buf), "%s Transport", text); + DoCommand(0, 0, 0, DC_EXEC, CMD_RENAME_COMPANY, buf); + } + } + + MarkWholeScreenDirty(); + CompanyAdminUpdate(c); + } + + return CommandCost(); +} + +/** + * Get the service interval for the given company and vehicle type. + * @param c The company, or NULL for client-default settings. + * @param type The vehicle type to get the interval for. + * @return The service interval. + */ +int CompanyServiceInterval(const Company *c, VehicleType type) +{ + const VehicleDefaultSettings *vds = (c == NULL) ? &_settings_client.company.vehicle : &c->settings.vehicle; + switch (type) { + default: NOT_REACHED(); + case VEH_TRAIN: return vds->servint_trains; + case VEH_ROAD: return vds->servint_roadveh; + case VEH_AIRCRAFT: return vds->servint_aircraft; + case VEH_SHIP: return vds->servint_ships; + } +} diff --git a/src/company_func.h b/src/company_func.h new file mode 100644 index 0000000..29650d7 --- /dev/null +++ b/src/company_func.h @@ -0,0 +1,62 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file company_func.h Functions related to companies. */ + +#ifndef COMPANY_FUNC_H +#define COMPANY_FUNC_H + +#include "command_type.h" +#include "company_type.h" +#include "gfx_type.h" +#include "vehicle_type.h" + +bool MayCompanyTakeOver(CompanyID cbig, CompanyID small); +void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner); +void GetNameOfOwner(Owner owner, TileIndex tile); +void SetLocalCompany(CompanyID new_company); +void ShowBuyCompanyDialog(CompanyID company); +void CompanyAdminUpdate(const Company *company); +void CompanyAdminBankrupt(CompanyID company_id); +void UpdateLandscapingLimits(); + +bool CheckCompanyHasMoney(CommandCost &cost); +void SubtractMoneyFromCompany(CommandCost cost); +void SubtractMoneyFromCompanyFract(CompanyID company, CommandCost cost); +CommandCost CheckOwnership(Owner owner, TileIndex tile = 0); +CommandCost CheckTileOwnership(TileIndex tile); + +extern CompanyByte _local_company; +extern CompanyByte _current_company; + +extern Colours _company_colours[MAX_COMPANIES]; +extern CompanyManagerFace _company_manager_face; + +/** + * Is the current company the local company? + * @return \c true of the current company is the local company, \c false otherwise. + */ +static inline bool IsLocalCompany() +{ + return _local_company == _current_company; +} + +/** + * Is the user representing \a company? + * @param company Company where interaction is needed with. + * @return Gives \c true if the user can answer questions interactively as representative of \a company, else \c false + */ +static inline bool IsInteractiveCompany(CompanyID company) +{ + return company == _local_company; +} + +int CompanyServiceInterval(const Company *c, VehicleType type); + +#endif /* COMPANY_FUNC_H */ diff --git a/src/company_gui.cpp b/src/company_gui.cpp new file mode 100644 index 0000000..cbd943e --- /dev/null +++ b/src/company_gui.cpp @@ -0,0 +1,2579 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file company_gui.cpp %Company related GUIs. */ + +#include "stdafx.h" +#include "error.h" +#include "gui.h" +#include "window_gui.h" +#include "textbuf_gui.h" +#include "viewport_func.h" +#include "company_func.h" +#include "command_func.h" +#include "network/network.h" +#include "network/network_gui.h" +#include "network/network_func.h" +#include "newgrf.h" +#include "company_manager_face.h" +#include "strings_func.h" +#include "date_func.h" +#include "widgets/dropdown_type.h" +#include "tilehighlight_func.h" +#include "company_base.h" +#include "core/geometry_func.hpp" +#include "object_type.h" +#include "rail.h" +#include "engine_base.h" +#include "window_func.h" +#include "road_func.h" +#include "water.h" +#include "station_func.h" +#include "zoom_func.h" + +#include "widgets/company_widget.h" + +#include "safeguards.h" + + +/** Company GUI constants. */ +static const uint EXP_LINESPACE = 2; ///< Amount of vertical space for a horizontal (sub-)total line. +static const uint EXP_BLOCKSPACE = 10; ///< Amount of vertical space between two blocks of numbers. + +static void DoSelectCompanyManagerFace(Window *parent); +static void ShowCompanyInfrastructure(CompanyID company); + +/** Standard unsorted list of expenses. */ +static ExpensesType _expenses_list_1[] = { + EXPENSES_CONSTRUCTION, + EXPENSES_NEW_VEHICLES, + EXPENSES_TRAIN_RUN, + EXPENSES_ROADVEH_RUN, + EXPENSES_AIRCRAFT_RUN, + EXPENSES_SHIP_RUN, + EXPENSES_PROPERTY, + EXPENSES_TRAIN_INC, + EXPENSES_ROADVEH_INC, + EXPENSES_AIRCRAFT_INC, + EXPENSES_SHIP_INC, + EXPENSES_LOAN_INT, + EXPENSES_SHARING_INC, + EXPENSES_SHARING_COST, + EXPENSES_OTHER, +}; + +/** Grouped list of expenses. */ +static ExpensesType _expenses_list_2[] = { + EXPENSES_TRAIN_INC, + EXPENSES_ROADVEH_INC, + EXPENSES_AIRCRAFT_INC, + EXPENSES_SHIP_INC, + EXPENSES_SHARING_INC, + INVALID_EXPENSES, + EXPENSES_TRAIN_RUN, + EXPENSES_ROADVEH_RUN, + EXPENSES_AIRCRAFT_RUN, + EXPENSES_SHIP_RUN, + EXPENSES_SHARING_COST, + EXPENSES_PROPERTY, + EXPENSES_LOAN_INT, + INVALID_EXPENSES, + EXPENSES_CONSTRUCTION, + EXPENSES_NEW_VEHICLES, + EXPENSES_OTHER, + INVALID_EXPENSES, +}; + +/** Expense list container. */ +struct ExpensesList { + const ExpensesType *et; ///< Expenses items. + const uint length; ///< Number of items in list. + const uint num_subtotals; ///< Number of sub-totals in the list. + + ExpensesList(ExpensesType *et, int length, int num_subtotals) : et(et), length(length), num_subtotals(num_subtotals) + { + } + + uint GetHeight() const + { + /* heading + line + texts of expenses + sub-totals + total line + total text */ + return FONT_HEIGHT_NORMAL + EXP_LINESPACE + this->length * FONT_HEIGHT_NORMAL + num_subtotals * (EXP_BLOCKSPACE + EXP_LINESPACE) + EXP_LINESPACE + FONT_HEIGHT_NORMAL; + } + + /** Compute width of the expenses categories in pixels. */ + uint GetCategoriesWidth() const + { + uint width = 0; + bool invalid_expenses_measured = false; // Measure 'Total' width only once. + for (uint i = 0; i < this->length; i++) { + ExpensesType et = this->et[i]; + if (et == INVALID_EXPENSES) { + if (!invalid_expenses_measured) { + width = max(width, GetStringBoundingBox(STR_FINANCES_TOTAL_CAPTION).width); + invalid_expenses_measured = true; + } + } else { + width = max(width, GetStringBoundingBox(STR_FINANCES_SECTION_CONSTRUCTION + et).width); + } + } + return width; + } +}; + +static const ExpensesList _expenses_list_types[] = { + ExpensesList(_expenses_list_1, lengthof(_expenses_list_1), 0), + ExpensesList(_expenses_list_2, lengthof(_expenses_list_2), 3), +}; + +/** + * Draw the expenses categories. + * @param r Available space for drawing. + * @note The environment must provide padding at the left and right of \a r. + */ +static void DrawCategories(const Rect &r) +{ + int y = r.top; + + DrawString(r.left, r.right, y, STR_FINANCES_EXPENDITURE_INCOME_TITLE, TC_FROMSTRING, SA_HOR_CENTER, true); + y += FONT_HEIGHT_NORMAL + EXP_LINESPACE; + + int type = _settings_client.gui.expenses_layout; + for (uint i = 0; i < _expenses_list_types[type].length; i++) { + const ExpensesType et = _expenses_list_types[type].et[i]; + if (et == INVALID_EXPENSES) { + y += EXP_LINESPACE; + DrawString(r.left, r.right, y, STR_FINANCES_TOTAL_CAPTION, TC_FROMSTRING, SA_RIGHT); + y += FONT_HEIGHT_NORMAL + EXP_BLOCKSPACE; + } else { + DrawString(r.left, r.right, y, STR_FINANCES_SECTION_CONSTRUCTION + et); + y += FONT_HEIGHT_NORMAL; + } + } + + DrawString(r.left, r.right, y + EXP_LINESPACE, STR_FINANCES_TOTAL_CAPTION, TC_FROMSTRING, SA_RIGHT); +} + +/** + * Draw an amount of money. + * @param amount Amount of money to draw, + * @param left Left coordinate of the space to draw in. + * @param right Right coordinate of the space to draw in. + * @param top Top coordinate of the space to draw in. + */ +static void DrawPrice(Money amount, int left, int right, int top) +{ + StringID str = STR_FINANCES_NEGATIVE_INCOME; + if (amount < 0) { + amount = -amount; + str++; + } + SetDParam(0, amount); + DrawString(left, right, top, str, TC_FROMSTRING, SA_RIGHT); +} + +/** + * Draw a column with prices. + * @param r Available space for drawing. + * @param year Year being drawn. + * @param tbl Pointer to table of amounts for \a year. + * @note The environment must provide padding at the left and right of \a r. + */ +static void DrawYearColumn(const Rect &r, int year, const Money (*tbl)[EXPENSES_END]) +{ + int y = r.top; + + SetDParam(0, year); + DrawString(r.left, r.right, y, STR_FINANCES_YEAR, TC_FROMSTRING, SA_RIGHT, true); + y += FONT_HEIGHT_NORMAL + EXP_LINESPACE; + + Money sum = 0; + Money subtotal = 0; + int type = _settings_client.gui.expenses_layout; + for (uint i = 0; i < _expenses_list_types[type].length; i++) { + const ExpensesType et = _expenses_list_types[type].et[i]; + if (et == INVALID_EXPENSES) { + Money cost = subtotal; + subtotal = 0; + GfxFillRect(r.left, y, r.right, y, PC_BLACK); + y += EXP_LINESPACE; + DrawPrice(cost, r.left, r.right, y); + y += FONT_HEIGHT_NORMAL + EXP_BLOCKSPACE; + } else { + Money cost = (*tbl)[et]; + subtotal += cost; + sum += cost; + if (cost != 0) DrawPrice(cost, r.left, r.right, y); + y += FONT_HEIGHT_NORMAL; + } + } + + GfxFillRect(r.left, y, r.right, y, PC_BLACK); + y += EXP_LINESPACE; + DrawPrice(sum, r.left, r.right, y); +} + +static const NWidgetPart _nested_company_finances_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_CF_CAPTION), SetDataTip(STR_FINANCES_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_CF_TOGGLE_SIZE), SetDataTip(SPR_LARGE_SMALL_WINDOW, STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW), + NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_STICKYBOX, COLOUR_GREY), + EndContainer(), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_CF_SEL_PANEL), + NWidget(WWT_PANEL, COLOUR_GREY), + NWidget(NWID_HORIZONTAL), SetPadding(WD_FRAMERECT_TOP, WD_FRAMERECT_RIGHT, WD_FRAMERECT_BOTTOM, WD_FRAMERECT_LEFT), SetPIP(0, 9, 0), + NWidget(WWT_EMPTY, COLOUR_GREY, WID_CF_EXPS_CATEGORY), SetMinimalSize(120, 0), SetFill(0, 0), + NWidget(WWT_EMPTY, COLOUR_GREY, WID_CF_EXPS_PRICE1), SetMinimalSize(86, 0), SetFill(0, 0), + NWidget(WWT_EMPTY, COLOUR_GREY, WID_CF_EXPS_PRICE2), SetMinimalSize(86, 0), SetFill(0, 0), + NWidget(WWT_EMPTY, COLOUR_GREY, WID_CF_EXPS_PRICE3), SetMinimalSize(86, 0), SetFill(0, 0), + EndContainer(), + EndContainer(), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), + NWidget(NWID_HORIZONTAL), SetPadding(WD_FRAMERECT_TOP, WD_FRAMERECT_RIGHT, WD_FRAMERECT_BOTTOM, WD_FRAMERECT_LEFT), + NWidget(NWID_VERTICAL), // Vertical column with 'bank balance', 'loan' + NWidget(WWT_TEXT, COLOUR_GREY), SetDataTip(STR_FINANCES_BANK_BALANCE_TITLE, STR_NULL), SetFill(1, 0), + NWidget(WWT_TEXT, COLOUR_GREY), SetDataTip(STR_FINANCES_LOAN_TITLE, STR_NULL), SetFill(1, 0), + NWidget(NWID_SPACER), SetFill(0, 1), + EndContainer(), + NWidget(NWID_SPACER), SetFill(0, 0), SetMinimalSize(30, 0), + NWidget(NWID_VERTICAL), // Vertical column with bank balance amount, loan amount, and total. + NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_BALANCE_VALUE), SetDataTip(STR_NULL, STR_NULL), + NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_LOAN_VALUE), SetDataTip(STR_NULL, STR_NULL), + NWidget(WWT_EMPTY, COLOUR_GREY, WID_CF_LOAN_LINE), SetMinimalSize(0, 2), SetFill(1, 0), + NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_TOTAL_VALUE), SetDataTip(STR_NULL, STR_NULL), + EndContainer(), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_CF_SEL_MAXLOAN), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_SPACER), SetFill(0, 1), SetMinimalSize(25, 0), + NWidget(NWID_VERTICAL), // Max loan information + NWidget(WWT_EMPTY, COLOUR_GREY, WID_CF_MAXLOAN_GAP), SetFill(0, 0), + NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_MAXLOAN_VALUE), SetDataTip(STR_FINANCES_MAX_LOAN, STR_NULL), + NWidget(NWID_SPACER), SetFill(0, 1), + EndContainer(), + EndContainer(), + EndContainer(), + NWidget(NWID_SPACER), SetFill(1, 1), + EndContainer(), + EndContainer(), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_CF_SEL_BUTTONS), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_CF_INCREASE_LOAN), SetFill(1, 0), SetDataTip(STR_FINANCES_BORROW_BUTTON, STR_FINANCES_BORROW_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_CF_REPAY_LOAN), SetFill(1, 0), SetDataTip(STR_FINANCES_REPAY_BUTTON, STR_FINANCES_REPAY_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_CF_INFRASTRUCTURE), SetFill(1, 0), SetDataTip(STR_FINANCES_INFRASTRUCTURE_BUTTON, STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP), + EndContainer(), + EndContainer(), +}; + +/** + * Window class displaying the company finances. + * @todo #money_width should be calculated dynamically. + */ +struct CompanyFinancesWindow : Window { + static Money max_money; ///< The maximum amount of money a company has had this 'run' + bool small; ///< Window is toggled to 'small'. + + CompanyFinancesWindow(WindowDesc *desc, CompanyID company) : Window(desc) + { + this->small = false; + this->CreateNestedTree(); + this->SetupWidgets(); + this->FinishInitNested(company); + + this->owner = (Owner)this->window_number; + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_CF_CAPTION: + SetDParam(0, (CompanyID)this->window_number); + SetDParam(1, (CompanyID)this->window_number); + break; + + case WID_CF_MAXLOAN_VALUE: + SetDParam(0, _economy.max_loan); + break; + + case WID_CF_INCREASE_LOAN: + case WID_CF_REPAY_LOAN: + SetDParam(0, LOAN_INTERVAL); + break; + } + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + int type = _settings_client.gui.expenses_layout; + switch (widget) { + case WID_CF_EXPS_CATEGORY: + size->width = _expenses_list_types[type].GetCategoriesWidth(); + size->height = _expenses_list_types[type].GetHeight(); + break; + + case WID_CF_EXPS_PRICE1: + case WID_CF_EXPS_PRICE2: + case WID_CF_EXPS_PRICE3: + size->height = _expenses_list_types[type].GetHeight(); + /* FALL THROUGH */ + case WID_CF_BALANCE_VALUE: + case WID_CF_LOAN_VALUE: + case WID_CF_TOTAL_VALUE: + SetDParamMaxValue(0, CompanyFinancesWindow::max_money); + size->width = max(GetStringBoundingBox(STR_FINANCES_NEGATIVE_INCOME).width, GetStringBoundingBox(STR_FINANCES_POSITIVE_INCOME).width) + padding.width; + break; + + case WID_CF_MAXLOAN_GAP: + size->height = FONT_HEIGHT_NORMAL; + break; + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_CF_EXPS_CATEGORY: + DrawCategories(r); + break; + + case WID_CF_EXPS_PRICE1: + case WID_CF_EXPS_PRICE2: + case WID_CF_EXPS_PRICE3: { + const Company *c = Company::Get((CompanyID)this->window_number); + int age = min(_cur_year - c->inaugurated_year, 2); + int wid_offset = widget - WID_CF_EXPS_PRICE1; + if (wid_offset <= age) { + DrawYearColumn(r, _cur_year - (age - wid_offset), c->yearly_expenses + (age - wid_offset)); + } + break; + } + + case WID_CF_BALANCE_VALUE: { + const Company *c = Company::Get((CompanyID)this->window_number); + SetDParam(0, c->money); + DrawString(r.left, r.right, r.top, STR_FINANCES_TOTAL_CURRENCY, TC_FROMSTRING, SA_RIGHT); + break; + } + + case WID_CF_LOAN_VALUE: { + const Company *c = Company::Get((CompanyID)this->window_number); + SetDParam(0, c->current_loan); + DrawString(r.left, r.right, r.top, STR_FINANCES_TOTAL_CURRENCY, TC_FROMSTRING, SA_RIGHT); + break; + } + + case WID_CF_TOTAL_VALUE: { + const Company *c = Company::Get((CompanyID)this->window_number); + SetDParam(0, c->money - c->current_loan); + DrawString(r.left, r.right, r.top, STR_FINANCES_TOTAL_CURRENCY, TC_FROMSTRING, SA_RIGHT); + break; + } + + case WID_CF_LOAN_LINE: + GfxFillRect(r.left, r.top, r.right, r.top, PC_BLACK); + break; + } + } + + /** + * Setup the widgets in the nested tree, such that the finances window is displayed properly. + * @note After setup, the window must be (re-)initialized. + */ + void SetupWidgets() + { + int plane = this->small ? SZSP_NONE : 0; + this->GetWidget(WID_CF_SEL_PANEL)->SetDisplayedPlane(plane); + this->GetWidget(WID_CF_SEL_MAXLOAN)->SetDisplayedPlane(plane); + + CompanyID company = (CompanyID)this->window_number; + plane = (company != _local_company) ? SZSP_NONE : 0; + this->GetWidget(WID_CF_SEL_BUTTONS)->SetDisplayedPlane(plane); + } + + virtual void OnPaint() + { + if (!this->IsShaded()) { + if (!this->small) { + /* Check that the expenses panel height matches the height needed for the layout. */ + int type = _settings_client.gui.expenses_layout; + if (_expenses_list_types[type].GetHeight() != this->GetWidget(WID_CF_EXPS_CATEGORY)->current_y) { + this->SetupWidgets(); + this->ReInit(); + return; + } + } + + /* Check that the loan buttons are shown only when the user owns the company. */ + CompanyID company = (CompanyID)this->window_number; + int req_plane = (company != _local_company) ? SZSP_NONE : 0; + if (req_plane != this->GetWidget(WID_CF_SEL_BUTTONS)->shown_plane) { + this->SetupWidgets(); + this->ReInit(); + return; + } + + const Company *c = Company::Get(company); + this->SetWidgetDisabledState(WID_CF_INCREASE_LOAN, c->current_loan == _economy.max_loan); // Borrow button only shows when there is any more money to loan. + this->SetWidgetDisabledState(WID_CF_REPAY_LOAN, company != _local_company || c->current_loan == 0); // Repay button only shows when there is any more money to repay. + } + + this->DrawWidgets(); + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_CF_TOGGLE_SIZE: // toggle size + this->small = !this->small; + this->SetupWidgets(); + if (this->IsShaded()) { + /* Finances window is not resizable, so size hints given during unshading have no effect + * on the changed appearance of the window. */ + this->SetShaded(false); + } else { + this->ReInit(); + } + break; + + case WID_CF_INCREASE_LOAN: // increase loan + DoCommandP(0, 0, _ctrl_pressed, CMD_INCREASE_LOAN | CMD_MSG(STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY)); + break; + + case WID_CF_REPAY_LOAN: // repay loan + DoCommandP(0, 0, _ctrl_pressed, CMD_DECREASE_LOAN | CMD_MSG(STR_ERROR_CAN_T_REPAY_LOAN)); + break; + + case WID_CF_INFRASTRUCTURE: // show infrastructure details + ShowCompanyInfrastructure((CompanyID)this->window_number); + break; + } + } + + virtual void OnHundredthTick() + { + const Company *c = Company::Get((CompanyID)this->window_number); + if (c->money > CompanyFinancesWindow::max_money) { + CompanyFinancesWindow::max_money = max(c->money * 2, CompanyFinancesWindow::max_money * 4); + this->SetupWidgets(); + this->ReInit(); + } + } +}; + +/** First conservative estimate of the maximum amount of money */ +Money CompanyFinancesWindow::max_money = INT32_MAX; + +static WindowDesc _company_finances_desc( + WDP_AUTO, "company_finances", 0, 0, + WC_FINANCES, WC_NONE, + 0, + _nested_company_finances_widgets, lengthof(_nested_company_finances_widgets) +); + +/** + * Open the finances window of a company. + * @param company Company to show finances of. + * @pre is company a valid company. + */ +void ShowCompanyFinances(CompanyID company) +{ + if (!Company::IsValidID(company)) return; + if (BringWindowToFrontById(WC_FINANCES, company)) return; + + new CompanyFinancesWindow(&_company_finances_desc, company); +} + +/* List of colours for the livery window */ +static const StringID _colour_dropdown[] = { + STR_COLOUR_DARK_BLUE, + STR_COLOUR_PALE_GREEN, + STR_COLOUR_PINK, + STR_COLOUR_YELLOW, + STR_COLOUR_RED, + STR_COLOUR_LIGHT_BLUE, + STR_COLOUR_GREEN, + STR_COLOUR_DARK_GREEN, + STR_COLOUR_BLUE, + STR_COLOUR_CREAM, + STR_COLOUR_MAUVE, + STR_COLOUR_PURPLE, + STR_COLOUR_ORANGE, + STR_COLOUR_BROWN, + STR_COLOUR_GREY, + STR_COLOUR_WHITE, +}; + +/* Association of liveries to livery classes */ +static const LiveryClass _livery_class[LS_END] = { + LC_OTHER, + LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, + LC_ROAD, LC_ROAD, + LC_SHIP, LC_SHIP, + LC_AIRCRAFT, LC_AIRCRAFT, LC_AIRCRAFT, + LC_ROAD, LC_ROAD, +}; + +class DropDownListColourItem : public DropDownListItem { +public: + DropDownListColourItem(int result, bool masked) : DropDownListItem(result, masked) {} + + virtual ~DropDownListColourItem() {} + + StringID String() const + { + return _colour_dropdown[this->result]; + } + + uint Height(uint width) const + { + return max(FONT_HEIGHT_NORMAL, ScaleGUITrad(12) + 2); + } + + bool Selectable() const + { + return true; + } + + void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const + { + bool rtl = _current_text_dir == TD_RTL; + int height = bottom - top; + int icon_y_offset = height / 2; + int text_y_offset = (height - FONT_HEIGHT_NORMAL) / 2 + 1; + DrawSprite(SPR_VEH_BUS_SIDE_VIEW, PALETTE_RECOLOUR_START + this->result, + rtl ? right - 2 - ScaleGUITrad(14) : left + ScaleGUITrad(14) + 2, + top + icon_y_offset); + DrawString(rtl ? left + 2 : left + ScaleGUITrad(28) + 4, + rtl ? right - ScaleGUITrad(28) - 4 : right - 2, + top + text_y_offset, this->String(), sel ? TC_WHITE : TC_BLACK); + } +}; + +/** Company livery colour scheme window. */ +struct SelectCompanyLiveryWindow : public Window { +private: + uint32 sel; + LiveryClass livery_class; + Dimension square; + Dimension box; + uint line_height; + + void ShowColourDropDownMenu(uint32 widget) + { + uint32 used_colours = 0; + const Livery *livery; + LiveryScheme scheme; + + /* Disallow other company colours for the primary colour */ + if (HasBit(this->sel, LS_DEFAULT) && widget == WID_SCL_PRI_COL_DROPDOWN) { + const Company *c; + FOR_ALL_COMPANIES(c) { + if (c->index != _local_company) SetBit(used_colours, c->colour); + } + } + + /* Get the first selected livery to use as the default dropdown item */ + for (scheme = LS_BEGIN; scheme < LS_END; scheme++) { + if (HasBit(this->sel, scheme)) break; + } + if (scheme == LS_END) scheme = LS_DEFAULT; + livery = &Company::Get((CompanyID)this->window_number)->livery[scheme]; + + DropDownList *list = new DropDownList(); + for (uint i = 0; i < lengthof(_colour_dropdown); i++) { + *list->Append() = new DropDownListColourItem(i, HasBit(used_colours, i)); + } + + ShowDropDownList(this, list, widget == WID_SCL_PRI_COL_DROPDOWN ? livery->colour1 : livery->colour2, widget); + } + +public: + SelectCompanyLiveryWindow(WindowDesc *desc, CompanyID company) : Window(desc) + { + this->livery_class = LC_OTHER; + this->sel = 1; + + this->square = GetSpriteSize(SPR_SQUARE); + this->box = maxdim(GetSpriteSize(SPR_BOX_CHECKED), GetSpriteSize(SPR_BOX_EMPTY)); + this->line_height = max(max(this->square.height, this->box.height), (uint)FONT_HEIGHT_NORMAL) + 4; + + this->InitNested(company); + this->owner = company; + this->LowerWidget(WID_SCL_CLASS_GENERAL); + this->InvalidateData(1); + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_SCL_SPACER_DROPDOWN: { + /* The matrix widget below needs enough room to print all the schemes. */ + Dimension d = {0, 0}; + for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) { + d = maxdim(d, GetStringBoundingBox(STR_LIVERY_DEFAULT + scheme)); + } + size->width = max(size->width, 5 + this->box.width + d.width + WD_FRAMERECT_RIGHT); + break; + } + + case WID_SCL_MATRIX: { + uint livery_height = 0; + for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) { + if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) { + livery_height++; + } + } + size->height = livery_height * this->line_height; + this->GetWidget(WID_SCL_MATRIX)->widget_data = (livery_height << MAT_ROW_START) | (1 << MAT_COL_START); + break; + } + + case WID_SCL_SEC_COL_DROPDOWN: + if (!_loaded_newgrf_features.has_2CC) { + size->width = 0; + break; + } + /* FALL THROUGH */ + case WID_SCL_PRI_COL_DROPDOWN: { + int padding = this->square.width + NWidgetScrollbar::GetVerticalDimension().width + 10; + for (const StringID *id = _colour_dropdown; id != endof(_colour_dropdown); id++) { + size->width = max(size->width, GetStringBoundingBox(*id).width + padding); + } + break; + } + } + } + + virtual void OnPaint() + { + /* Disable dropdown controls if no scheme is selected */ + this->SetWidgetDisabledState(WID_SCL_PRI_COL_DROPDOWN, this->sel == 0); + this->SetWidgetDisabledState(WID_SCL_SEC_COL_DROPDOWN, this->sel == 0); + + this->DrawWidgets(); + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_SCL_PRI_COL_DROPDOWN: + case WID_SCL_SEC_COL_DROPDOWN: { + const Company *c = Company::Get((CompanyID)this->window_number); + LiveryScheme scheme = LS_DEFAULT; + + if (this->sel != 0) { + for (scheme = LS_BEGIN; scheme < LS_END; scheme++) { + if (HasBit(this->sel, scheme)) break; + } + if (scheme == LS_END) scheme = LS_DEFAULT; + } + SetDParam(0, STR_COLOUR_DARK_BLUE + ((widget == WID_SCL_PRI_COL_DROPDOWN) ? c->livery[scheme].colour1 : c->livery[scheme].colour2)); + break; + } + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + if (widget != WID_SCL_MATRIX) return; + + bool rtl = _current_text_dir == TD_RTL; + + /* Horizontal coordinates of scheme name column. */ + const NWidgetBase *nwi = this->GetWidget(WID_SCL_SPACER_DROPDOWN); + int sch_left = nwi->pos_x; + int sch_right = sch_left + nwi->current_x - 1; + /* Horizontal coordinates of first dropdown. */ + nwi = this->GetWidget(WID_SCL_PRI_COL_DROPDOWN); + int pri_left = nwi->pos_x; + int pri_right = pri_left + nwi->current_x - 1; + /* Horizontal coordinates of second dropdown. */ + nwi = this->GetWidget(WID_SCL_SEC_COL_DROPDOWN); + int sec_left = nwi->pos_x; + int sec_right = sec_left + nwi->current_x - 1; + + int text_left = (rtl ? (uint)WD_FRAMERECT_LEFT : (this->box.width + 5)); + int text_right = (rtl ? (this->box.width + 5) : (uint)WD_FRAMERECT_RIGHT); + + int box_offs = (this->line_height - this->box.height) / 2; + int square_offs = (this->line_height - this->square.height) / 2 + 1; + int text_offs = (this->line_height - FONT_HEIGHT_NORMAL) / 2 + 1; + + int y = r.top; + const Company *c = Company::Get((CompanyID)this->window_number); + for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) { + if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) { + bool sel = HasBit(this->sel, scheme) != 0; + + /* Optional check box + scheme name. */ + if (scheme != LS_DEFAULT) { + DrawSprite(c->livery[scheme].in_use ? SPR_BOX_CHECKED : SPR_BOX_EMPTY, PAL_NONE, (rtl ? sch_right - (this->box.width + 5) + WD_FRAMERECT_RIGHT : sch_left) + WD_FRAMERECT_LEFT, y + box_offs); + } + DrawString(sch_left + text_left, sch_right - text_right, y + text_offs, STR_LIVERY_DEFAULT + scheme, sel ? TC_WHITE : TC_BLACK); + + /* Text below the first dropdown. */ + DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOUR(c->livery[scheme].colour1), (rtl ? pri_right - (this->box.width + 5) + WD_FRAMERECT_RIGHT : pri_left) + WD_FRAMERECT_LEFT, y + square_offs); + DrawString(pri_left + text_left, pri_right - text_right, y + text_offs, STR_COLOUR_DARK_BLUE + c->livery[scheme].colour1, sel ? TC_WHITE : TC_GOLD); + + /* Text below the second dropdown. */ + if (sec_right > sec_left) { // Second dropdown has non-zero size. + DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOUR(c->livery[scheme].colour2), (rtl ? sec_right - (this->box.width + 5) + WD_FRAMERECT_RIGHT : sec_left) + WD_FRAMERECT_LEFT, y + square_offs); + DrawString(sec_left + text_left, sec_right - text_right, y + text_offs, STR_COLOUR_DARK_BLUE + c->livery[scheme].colour2, sel ? TC_WHITE : TC_GOLD); + } + + y += this->line_height; + } + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + /* Livery Class buttons */ + case WID_SCL_CLASS_GENERAL: + case WID_SCL_CLASS_RAIL: + case WID_SCL_CLASS_ROAD: + case WID_SCL_CLASS_SHIP: + case WID_SCL_CLASS_AIRCRAFT: + this->RaiseWidget(this->livery_class + WID_SCL_CLASS_GENERAL); + this->livery_class = (LiveryClass)(widget - WID_SCL_CLASS_GENERAL); + this->LowerWidget(this->livery_class + WID_SCL_CLASS_GENERAL); + + /* Select the first item in the list */ + this->sel = 0; + for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) { + if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) { + this->sel = 1 << scheme; + break; + } + } + + this->ReInit(); + break; + + case WID_SCL_PRI_COL_DROPDOWN: // First colour dropdown + ShowColourDropDownMenu(WID_SCL_PRI_COL_DROPDOWN); + break; + + case WID_SCL_SEC_COL_DROPDOWN: // Second colour dropdown + ShowColourDropDownMenu(WID_SCL_SEC_COL_DROPDOWN); + break; + + case WID_SCL_MATRIX: { + const NWidgetBase *wid = this->GetWidget(WID_SCL_MATRIX); + LiveryScheme j = (LiveryScheme)((pt.y - wid->pos_y) / this->line_height); + + for (LiveryScheme scheme = LS_BEGIN; scheme <= j; scheme++) { + if (_livery_class[scheme] != this->livery_class || !HasBit(_loaded_newgrf_features.used_liveries, scheme)) j++; + if (scheme >= LS_END) return; + } + if (j >= LS_END) return; + + /* If clicking on the left edge, toggle using the livery */ + if (_current_text_dir == TD_RTL ? pt.x - wid->pos_x > wid->current_x - (this->box.width + 5) : pt.x - wid->pos_x < (this->box.width + 5)) { + DoCommandP(0, j | (2 << 8), !Company::Get((CompanyID)this->window_number)->livery[j].in_use, CMD_SET_COMPANY_COLOUR); + } + + if (_ctrl_pressed) { + ToggleBit(this->sel, j); + } else { + this->sel = 1 << j; + } + this->SetDirty(); + break; + } + } + } + + virtual void OnDropdownSelect(int widget, int index) + { + for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) { + /* Changed colour for the selected scheme, or all visible schemes if CTRL is pressed. */ + if (HasBit(this->sel, scheme) || (_ctrl_pressed && _livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme))) { + DoCommandP(0, scheme | (widget == WID_SCL_PRI_COL_DROPDOWN ? 0 : 256), index, CMD_SET_COMPANY_COLOUR); + } + } + } + + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (!gui_scope) return; + this->SetWidgetsDisabledState(true, WID_SCL_CLASS_RAIL, WID_SCL_CLASS_ROAD, WID_SCL_CLASS_SHIP, WID_SCL_CLASS_AIRCRAFT, WIDGET_LIST_END); + + bool current_class_valid = this->livery_class == LC_OTHER; + if (_settings_client.gui.liveries == LIT_ALL || (_settings_client.gui.liveries == LIT_COMPANY && this->window_number == _local_company)) { + for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) { + if (HasBit(_loaded_newgrf_features.used_liveries, scheme)) { + if (_livery_class[scheme] == this->livery_class) current_class_valid = true; + this->EnableWidget(WID_SCL_CLASS_GENERAL + _livery_class[scheme]); + } else { + ClrBit(this->sel, scheme); + } + } + } + + if (!current_class_valid) { + Point pt = {0, 0}; + this->OnClick(pt, WID_SCL_CLASS_GENERAL, 1); + } else if (data == 0) { + this->ReInit(); + } + } +}; + +static const NWidgetPart _nested_select_company_livery_widgets [] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_SCL_CAPTION), SetDataTip(STR_LIVERY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_GENERAL), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_COMPANY_GENERAL, STR_LIVERY_GENERAL_TOOLTIP), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_RAIL), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TRAINLIST, STR_LIVERY_TRAIN_TOOLTIP), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_ROAD), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TRUCKLIST, STR_LIVERY_ROAD_VEHICLE_TOOLTIP), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_SHIP), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_SHIPLIST, STR_LIVERY_SHIP_TOOLTIP), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_AIRCRAFT), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_AIRPLANESLIST, STR_LIVERY_AIRCRAFT_TOOLTIP), + NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(90, 22), SetFill(1, 1), EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PANEL, COLOUR_GREY, WID_SCL_SPACER_DROPDOWN), SetMinimalSize(150, 12), SetFill(1, 1), EndContainer(), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SCL_PRI_COL_DROPDOWN), SetMinimalSize(125, 12), SetFill(0, 1), SetDataTip(STR_BLACK_STRING, STR_LIVERY_PRIMARY_TOOLTIP), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SCL_SEC_COL_DROPDOWN), SetMinimalSize(125, 12), SetFill(0, 1), + SetDataTip(STR_BLACK_STRING, STR_LIVERY_SECONDARY_TOOLTIP), + EndContainer(), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_SCL_MATRIX), SetMinimalSize(275, 15), SetFill(1, 0), SetMatrixDataTip(1, 1, STR_LIVERY_PANEL_TOOLTIP), +}; + +static WindowDesc _select_company_livery_desc( + WDP_AUTO, "company_livery", 0, 0, + WC_COMPANY_COLOUR, WC_NONE, + 0, + _nested_select_company_livery_widgets, lengthof(_nested_select_company_livery_widgets) +); + +/** + * Draws the face of a company manager's face. + * @param cmf the company manager's face + * @param colour the (background) colour of the gradient + * @param x x-position to draw the face + * @param y y-position to draw the face + */ +void DrawCompanyManagerFace(CompanyManagerFace cmf, int colour, int x, int y) +{ + GenderEthnicity ge = (GenderEthnicity)GetCompanyManagerFaceBits(cmf, CMFV_GEN_ETHN, GE_WM); + + bool has_moustache = !HasBit(ge, GENDER_FEMALE) && GetCompanyManagerFaceBits(cmf, CMFV_HAS_MOUSTACHE, ge) != 0; + bool has_tie_earring = !HasBit(ge, GENDER_FEMALE) || GetCompanyManagerFaceBits(cmf, CMFV_HAS_TIE_EARRING, ge) != 0; + bool has_glasses = GetCompanyManagerFaceBits(cmf, CMFV_HAS_GLASSES, ge) != 0; + PaletteID pal; + + /* Modify eye colour palette only if 2 or more valid values exist */ + if (_cmf_info[CMFV_EYE_COLOUR].valid_values[ge] < 2) { + pal = PAL_NONE; + } else { + switch (GetCompanyManagerFaceBits(cmf, CMFV_EYE_COLOUR, ge)) { + default: NOT_REACHED(); + case 0: pal = PALETTE_TO_BROWN; break; + case 1: pal = PALETTE_TO_BLUE; break; + case 2: pal = PALETTE_TO_GREEN; break; + } + } + + /* Draw the gradient (background) */ + DrawSprite(SPR_GRADIENT, GENERAL_SPRITE_COLOUR(colour), x, y); + + for (CompanyManagerFaceVariable cmfv = CMFV_CHEEKS; cmfv < CMFV_END; cmfv++) { + switch (cmfv) { + case CMFV_MOUSTACHE: if (!has_moustache) continue; break; + case CMFV_LIPS: // FALL THROUGH + case CMFV_NOSE: if (has_moustache) continue; break; + case CMFV_TIE_EARRING: if (!has_tie_earring) continue; break; + case CMFV_GLASSES: if (!has_glasses) continue; break; + default: break; + } + DrawSprite(GetCompanyManagerFaceSprite(cmf, cmfv, ge), (cmfv == CMFV_EYEBROWS) ? pal : PAL_NONE, x, y); + } +} + +/** Nested widget description for the company manager face selection dialog */ +static const NWidgetPart _nested_select_company_manager_face_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_SCMF_CAPTION), SetDataTip(STR_FACE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCMF_TOGGLE_LARGE_SMALL), SetDataTip(SPR_LARGE_SMALL_WINDOW, STR_FACE_ADVANCED_TOOLTIP), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_SCMF_SELECT_FACE), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(NWID_HORIZONTAL), SetPIP(2, 2, 2), + NWidget(NWID_VERTICAL), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_SPACER), SetFill(1, 0), + NWidget(WWT_EMPTY, COLOUR_GREY, WID_SCMF_FACE), SetMinimalSize(92, 119), + NWidget(NWID_SPACER), SetFill(1, 0), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_RANDOM_NEW_FACE), SetFill(1, 0), SetDataTip(STR_FACE_NEW_FACE_BUTTON, STR_FACE_NEW_FACE_TOOLTIP), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SCMF_SEL_LOADSAVE), // Load/number/save buttons under the portrait in the advanced view. + NWidget(NWID_VERTICAL), + NWidget(NWID_SPACER), SetMinimalSize(0, 5), SetFill(0, 1), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_LOAD), SetFill(1, 0), SetDataTip(STR_FACE_LOAD, STR_FACE_LOAD_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_FACECODE), SetFill(1, 0), SetDataTip(STR_FACE_FACECODE, STR_FACE_FACECODE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_SAVE), SetFill(1, 0), SetDataTip(STR_FACE_SAVE, STR_FACE_SAVE_TOOLTIP), + NWidget(NWID_SPACER), SetMinimalSize(0, 5), SetFill(0, 1), + EndContainer(), + EndContainer(), + EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON), SetFill(1, 0), SetDataTip(STR_FACE_ADVANCED, STR_FACE_ADVANCED_TOOLTIP), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SCMF_SEL_MALEFEMALE), // Simple male/female face setting. + NWidget(NWID_VERTICAL), + NWidget(NWID_SPACER), SetFill(0, 1), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_MALE), SetFill(1, 0), SetDataTip(STR_FACE_MALE_BUTTON, STR_FACE_MALE_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_FEMALE), SetFill(1, 0), SetDataTip(STR_FACE_FEMALE_BUTTON, STR_FACE_FEMALE_TOOLTIP), + NWidget(NWID_SPACER), SetFill(0, 1), + EndContainer(), + EndContainer(), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SCMF_SEL_PARTS), // Advanced face parts setting. + NWidget(NWID_VERTICAL), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_MALE2), SetFill(1, 0), SetDataTip(STR_FACE_MALE_BUTTON, STR_FACE_MALE_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_FEMALE2), SetFill(1, 0), SetDataTip(STR_FACE_FEMALE_BUTTON, STR_FACE_FEMALE_TOOLTIP), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_ETHNICITY_EUR), SetFill(1, 0), SetDataTip(STR_FACE_EUROPEAN, STR_FACE_SELECT_EUROPEAN), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_ETHNICITY_AFR), SetFill(1, 0), SetDataTip(STR_FACE_AFRICAN, STR_FACE_SELECT_AFRICAN), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 4), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_MOUSTACHE_EARRING), SetDataTip(STR_EMPTY, STR_FACE_MOUSTACHE_EARRING_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAS_GLASSES_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_GLASSES), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetFill(1, 0), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAIR_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_L), SetDataTip(AWV_DECREASE, STR_FACE_HAIR_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAIR), SetDataTip(STR_EMPTY, STR_FACE_HAIR_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_R), SetDataTip(AWV_INCREASE, STR_FACE_HAIR_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_EYEBROWS_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_L), SetDataTip(AWV_DECREASE, STR_FACE_EYEBROWS_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYEBROWS), SetDataTip(STR_EMPTY, STR_FACE_EYEBROWS_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_R), SetDataTip(AWV_INCREASE, STR_FACE_EYEBROWS_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_EYECOLOUR_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_L), SetDataTip(AWV_DECREASE, STR_FACE_EYECOLOUR_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR), SetDataTip(STR_EMPTY, STR_FACE_EYECOLOUR_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_R), SetDataTip(AWV_INCREASE, STR_FACE_EYECOLOUR_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_GLASSES_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_L), SetDataTip(AWV_DECREASE, STR_FACE_GLASSES_TOOLTIP_2), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_GLASSES), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP_2), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_R), SetDataTip(AWV_INCREASE, STR_FACE_GLASSES_TOOLTIP_2), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_NOSE_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_L), SetDataTip(AWV_DECREASE, STR_FACE_NOSE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_NOSE), SetDataTip(STR_EMPTY, STR_FACE_NOSE_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_R), SetDataTip(AWV_INCREASE, STR_FACE_NOSE_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_LIPS_MOUSTACHE_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_L), SetDataTip(AWV_DECREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE), SetDataTip(STR_EMPTY, STR_FACE_LIPS_MOUSTACHE_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_R), SetDataTip(AWV_INCREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_CHIN_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_L), SetDataTip(AWV_DECREASE, STR_FACE_CHIN_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_CHIN), SetDataTip(STR_EMPTY, STR_FACE_CHIN_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_R), SetDataTip(AWV_INCREASE, STR_FACE_CHIN_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_JACKET_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_L), SetDataTip(AWV_DECREASE, STR_FACE_JACKET_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_JACKET), SetDataTip(STR_EMPTY, STR_FACE_JACKET_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_R), SetDataTip(AWV_INCREASE, STR_FACE_JACKET_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_COLLAR_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_L), SetDataTip(AWV_DECREASE, STR_FACE_COLLAR_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_COLLAR), SetDataTip(STR_EMPTY, STR_FACE_COLLAR_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_R), SetDataTip(AWV_INCREASE, STR_FACE_COLLAR_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_TIE_EARRING_TEXT), SetFill(1, 0), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_L), SetDataTip(AWV_DECREASE, STR_FACE_TIE_EARRING_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING), SetDataTip(STR_EMPTY, STR_FACE_TIE_EARRING_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_R), SetDataTip(AWV_INCREASE, STR_FACE_TIE_EARRING_TOOLTIP), + EndContainer(), + NWidget(NWID_SPACER), SetFill(0, 1), + EndContainer(), + EndContainer(), + EndContainer(), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_CANCEL), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_FACE_CANCEL_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_ACCEPT), SetFill(1, 0), SetDataTip(STR_BUTTON_OK, STR_FACE_OK_TOOLTIP), + EndContainer(), +}; + +/** Management class for customizing the face of the company manager. */ +class SelectCompanyManagerFaceWindow : public Window +{ + CompanyManagerFace face; ///< company manager face bits + bool advanced; ///< advanced company manager face selection window + + GenderEthnicity ge; ///< Gender and ethnicity. + bool is_female; ///< Female face. + bool is_moust_male; ///< Male face with a moustache. + + Dimension yesno_dim; ///< Dimension of a yes/no button of a part in the advanced face window. + Dimension number_dim; ///< Dimension of a number widget of a part in the advanced face window. + + static const StringID PART_TEXTS_IS_FEMALE[]; ///< Strings depending on #is_female, used to describe parts (2 entries for a part). + static const StringID PART_TEXTS[]; ///< Fixed strings to describe parts of the face. + + /** + * Draw dynamic a label to the left of the button and a value in the button + * + * @param widget_index index of this widget in the window + * @param val the value which will be draw + * @param is_bool_widget is it a bool button + */ + void DrawFaceStringLabel(byte widget_index, uint8 val, bool is_bool_widget) const + { + StringID str; + const NWidgetCore *nwi_widget = this->GetWidget(widget_index); + if (!nwi_widget->IsDisabled()) { + if (is_bool_widget) { + /* if it a bool button write yes or no */ + str = (val != 0) ? STR_FACE_YES : STR_FACE_NO; + } else { + /* else write the value + 1 */ + SetDParam(0, val + 1); + str = STR_JUST_INT; + } + + /* Draw the value/bool in white (0xC). If the button clicked adds 1px to x and y text coordinates (IsWindowWidgetLowered()). */ + DrawString(nwi_widget->pos_x + nwi_widget->IsLowered(), nwi_widget->pos_x + nwi_widget->current_x - 1 - nwi_widget->IsLowered(), + nwi_widget->pos_y + 1 + nwi_widget->IsLowered(), str, TC_WHITE, SA_HOR_CENTER); + } + } + + void UpdateData() + { + this->ge = (GenderEthnicity)GB(this->face, _cmf_info[CMFV_GEN_ETHN].offset, _cmf_info[CMFV_GEN_ETHN].length); // get the gender and ethnicity + this->is_female = HasBit(this->ge, GENDER_FEMALE); // get the gender: 0 == male and 1 == female + this->is_moust_male = !is_female && GetCompanyManagerFaceBits(this->face, CMFV_HAS_MOUSTACHE, this->ge) != 0; // is a male face with moustache + } + +public: + SelectCompanyManagerFaceWindow(WindowDesc *desc, Window *parent) : Window(desc) + { + this->advanced = false; + this->CreateNestedTree(); + this->SelectDisplayPlanes(this->advanced); + this->FinishInitNested(parent->window_number); + this->parent = parent; + this->owner = (Owner)this->window_number; + this->face = Company::Get((CompanyID)this->window_number)->face; + + this->UpdateData(); + } + + /** + * Select planes to display to the user with the #NWID_SELECTION widgets #WID_SCMF_SEL_LOADSAVE, #WID_SCMF_SEL_MALEFEMALE, and #WID_SCMF_SEL_PARTS. + * @param advanced Display advanced face management window. + */ + void SelectDisplayPlanes(bool advanced) + { + this->GetWidget(WID_SCMF_SEL_LOADSAVE)->SetDisplayedPlane(advanced ? 0 : SZSP_NONE); + this->GetWidget(WID_SCMF_SEL_PARTS)->SetDisplayedPlane(advanced ? 0 : SZSP_NONE); + this->GetWidget(WID_SCMF_SEL_MALEFEMALE)->SetDisplayedPlane(advanced ? SZSP_NONE : 0); + this->GetWidget(WID_SCMF_RANDOM_NEW_FACE)->widget_data = advanced ? STR_FACE_RANDOM : STR_FACE_NEW_FACE_BUTTON; + + NWidgetCore *wi = this->GetWidget(WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON); + if (advanced) { + wi->SetDataTip(STR_FACE_SIMPLE, STR_FACE_SIMPLE_TOOLTIP); + } else { + wi->SetDataTip(STR_FACE_ADVANCED, STR_FACE_ADVANCED_TOOLTIP); + } + } + + virtual void OnInit() + { + /* Size of the boolean yes/no button. */ + Dimension yesno_dim = maxdim(GetStringBoundingBox(STR_FACE_YES), GetStringBoundingBox(STR_FACE_NO)); + yesno_dim.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + yesno_dim.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + /* Size of the number button + arrows. */ + Dimension number_dim = {0, 0}; + for (int val = 1; val <= 12; val++) { + SetDParam(0, val); + number_dim = maxdim(number_dim, GetStringBoundingBox(STR_JUST_INT)); + } + uint arrows_width = GetSpriteSize(SPR_ARROW_LEFT).width + GetSpriteSize(SPR_ARROW_RIGHT).width + 2 * (WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT); + number_dim.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT + arrows_width; + number_dim.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + /* Compute width of both buttons. */ + yesno_dim.width = max(yesno_dim.width, number_dim.width); + number_dim.width = yesno_dim.width - arrows_width; + + this->yesno_dim = yesno_dim; + this->number_dim = number_dim; + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_SCMF_FACE: { + Dimension face_size = GetSpriteSize(SPR_GRADIENT); + size->width = max(size->width, face_size.width); + size->height = max(size->height, face_size.height); + break; + } + + case WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT: + case WID_SCMF_TIE_EARRING_TEXT: { + int offset = (widget - WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT) * 2; + *size = maxdim(GetStringBoundingBox(PART_TEXTS_IS_FEMALE[offset]), GetStringBoundingBox(PART_TEXTS_IS_FEMALE[offset + 1])); + size->width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + break; + } + + case WID_SCMF_LIPS_MOUSTACHE_TEXT: + *size = maxdim(GetStringBoundingBox(STR_FACE_LIPS), GetStringBoundingBox(STR_FACE_MOUSTACHE)); + size->width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + break; + + case WID_SCMF_HAS_GLASSES_TEXT: + case WID_SCMF_HAIR_TEXT: + case WID_SCMF_EYEBROWS_TEXT: + case WID_SCMF_EYECOLOUR_TEXT: + case WID_SCMF_GLASSES_TEXT: + case WID_SCMF_NOSE_TEXT: + case WID_SCMF_CHIN_TEXT: + case WID_SCMF_JACKET_TEXT: + case WID_SCMF_COLLAR_TEXT: + *size = GetStringBoundingBox(PART_TEXTS[widget - WID_SCMF_HAS_GLASSES_TEXT]); + size->width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + break; + + case WID_SCMF_HAS_MOUSTACHE_EARRING: + case WID_SCMF_HAS_GLASSES: + *size = this->yesno_dim; + break; + + case WID_SCMF_EYECOLOUR: + case WID_SCMF_CHIN: + case WID_SCMF_EYEBROWS: + case WID_SCMF_LIPS_MOUSTACHE: + case WID_SCMF_NOSE: + case WID_SCMF_HAIR: + case WID_SCMF_JACKET: + case WID_SCMF_COLLAR: + case WID_SCMF_TIE_EARRING: + case WID_SCMF_GLASSES: + *size = this->number_dim; + break; + } + } + + virtual void OnPaint() + { + /* lower the non-selected gender button */ + this->SetWidgetsLoweredState(!this->is_female, WID_SCMF_MALE, WID_SCMF_MALE2, WIDGET_LIST_END); + this->SetWidgetsLoweredState( this->is_female, WID_SCMF_FEMALE, WID_SCMF_FEMALE2, WIDGET_LIST_END); + + /* advanced company manager face selection window */ + + /* lower the non-selected ethnicity button */ + this->SetWidgetLoweredState(WID_SCMF_ETHNICITY_EUR, !HasBit(this->ge, ETHNICITY_BLACK)); + this->SetWidgetLoweredState(WID_SCMF_ETHNICITY_AFR, HasBit(this->ge, ETHNICITY_BLACK)); + + + /* Disable dynamically the widgets which CompanyManagerFaceVariable has less than 2 options + * (or in other words you haven't any choice). + * If the widgets depend on a HAS-variable and this is false the widgets will be disabled, too. */ + + /* Eye colour buttons */ + this->SetWidgetsDisabledState(_cmf_info[CMFV_EYE_COLOUR].valid_values[this->ge] < 2, + WID_SCMF_EYECOLOUR, WID_SCMF_EYECOLOUR_L, WID_SCMF_EYECOLOUR_R, WIDGET_LIST_END); + + /* Chin buttons */ + this->SetWidgetsDisabledState(_cmf_info[CMFV_CHIN].valid_values[this->ge] < 2, + WID_SCMF_CHIN, WID_SCMF_CHIN_L, WID_SCMF_CHIN_R, WIDGET_LIST_END); + + /* Eyebrows buttons */ + this->SetWidgetsDisabledState(_cmf_info[CMFV_EYEBROWS].valid_values[this->ge] < 2, + WID_SCMF_EYEBROWS, WID_SCMF_EYEBROWS_L, WID_SCMF_EYEBROWS_R, WIDGET_LIST_END); + + /* Lips or (if it a male face with a moustache) moustache buttons */ + this->SetWidgetsDisabledState(_cmf_info[this->is_moust_male ? CMFV_MOUSTACHE : CMFV_LIPS].valid_values[this->ge] < 2, + WID_SCMF_LIPS_MOUSTACHE, WID_SCMF_LIPS_MOUSTACHE_L, WID_SCMF_LIPS_MOUSTACHE_R, WIDGET_LIST_END); + + /* Nose buttons | male faces with moustache haven't any nose options */ + this->SetWidgetsDisabledState(_cmf_info[CMFV_NOSE].valid_values[this->ge] < 2 || this->is_moust_male, + WID_SCMF_NOSE, WID_SCMF_NOSE_L, WID_SCMF_NOSE_R, WIDGET_LIST_END); + + /* Hair buttons */ + this->SetWidgetsDisabledState(_cmf_info[CMFV_HAIR].valid_values[this->ge] < 2, + WID_SCMF_HAIR, WID_SCMF_HAIR_L, WID_SCMF_HAIR_R, WIDGET_LIST_END); + + /* Jacket buttons */ + this->SetWidgetsDisabledState(_cmf_info[CMFV_JACKET].valid_values[this->ge] < 2, + WID_SCMF_JACKET, WID_SCMF_JACKET_L, WID_SCMF_JACKET_R, WIDGET_LIST_END); + + /* Collar buttons */ + this->SetWidgetsDisabledState(_cmf_info[CMFV_COLLAR].valid_values[this->ge] < 2, + WID_SCMF_COLLAR, WID_SCMF_COLLAR_L, WID_SCMF_COLLAR_R, WIDGET_LIST_END); + + /* Tie/earring buttons | female faces without earring haven't any earring options */ + this->SetWidgetsDisabledState(_cmf_info[CMFV_TIE_EARRING].valid_values[this->ge] < 2 || + (this->is_female && GetCompanyManagerFaceBits(this->face, CMFV_HAS_TIE_EARRING, this->ge) == 0), + WID_SCMF_TIE_EARRING, WID_SCMF_TIE_EARRING_L, WID_SCMF_TIE_EARRING_R, WIDGET_LIST_END); + + /* Glasses buttons | faces without glasses haven't any glasses options */ + this->SetWidgetsDisabledState(_cmf_info[CMFV_GLASSES].valid_values[this->ge] < 2 || GetCompanyManagerFaceBits(this->face, CMFV_HAS_GLASSES, this->ge) == 0, + WID_SCMF_GLASSES, WID_SCMF_GLASSES_L, WID_SCMF_GLASSES_R, WIDGET_LIST_END); + + this->DrawWidgets(); + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT: + case WID_SCMF_TIE_EARRING_TEXT: { + StringID str = PART_TEXTS_IS_FEMALE[(widget - WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT) * 2 + this->is_female]; + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, str, TC_GOLD, SA_RIGHT); + break; + } + + case WID_SCMF_LIPS_MOUSTACHE_TEXT: + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, (this->is_moust_male) ? STR_FACE_MOUSTACHE : STR_FACE_LIPS, TC_GOLD, SA_RIGHT); + break; + + case WID_SCMF_HAS_GLASSES_TEXT: + case WID_SCMF_HAIR_TEXT: + case WID_SCMF_EYEBROWS_TEXT: + case WID_SCMF_EYECOLOUR_TEXT: + case WID_SCMF_GLASSES_TEXT: + case WID_SCMF_NOSE_TEXT: + case WID_SCMF_CHIN_TEXT: + case WID_SCMF_JACKET_TEXT: + case WID_SCMF_COLLAR_TEXT: + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, PART_TEXTS[widget - WID_SCMF_HAS_GLASSES_TEXT], TC_GOLD, SA_RIGHT); + break; + + + case WID_SCMF_HAS_MOUSTACHE_EARRING: + if (this->is_female) { // Only for female faces + this->DrawFaceStringLabel(WID_SCMF_HAS_MOUSTACHE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_HAS_TIE_EARRING, this->ge), true); + } else { // Only for male faces + this->DrawFaceStringLabel(WID_SCMF_HAS_MOUSTACHE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_HAS_MOUSTACHE, this->ge), true); + } + break; + + case WID_SCMF_TIE_EARRING: + this->DrawFaceStringLabel(WID_SCMF_TIE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_TIE_EARRING, this->ge), false); + break; + + case WID_SCMF_LIPS_MOUSTACHE: + if (this->is_moust_male) { // Only for male faces with moustache + this->DrawFaceStringLabel(WID_SCMF_LIPS_MOUSTACHE, GetCompanyManagerFaceBits(this->face, CMFV_MOUSTACHE, this->ge), false); + } else { // Only for female faces or male faces without moustache + this->DrawFaceStringLabel(WID_SCMF_LIPS_MOUSTACHE, GetCompanyManagerFaceBits(this->face, CMFV_LIPS, this->ge), false); + } + break; + + case WID_SCMF_HAS_GLASSES: + this->DrawFaceStringLabel(WID_SCMF_HAS_GLASSES, GetCompanyManagerFaceBits(this->face, CMFV_HAS_GLASSES, this->ge), true ); + break; + + case WID_SCMF_HAIR: + this->DrawFaceStringLabel(WID_SCMF_HAIR, GetCompanyManagerFaceBits(this->face, CMFV_HAIR, this->ge), false); + break; + + case WID_SCMF_EYEBROWS: + this->DrawFaceStringLabel(WID_SCMF_EYEBROWS, GetCompanyManagerFaceBits(this->face, CMFV_EYEBROWS, this->ge), false); + break; + + case WID_SCMF_EYECOLOUR: + this->DrawFaceStringLabel(WID_SCMF_EYECOLOUR, GetCompanyManagerFaceBits(this->face, CMFV_EYE_COLOUR, this->ge), false); + break; + + case WID_SCMF_GLASSES: + this->DrawFaceStringLabel(WID_SCMF_GLASSES, GetCompanyManagerFaceBits(this->face, CMFV_GLASSES, this->ge), false); + break; + + case WID_SCMF_NOSE: + this->DrawFaceStringLabel(WID_SCMF_NOSE, GetCompanyManagerFaceBits(this->face, CMFV_NOSE, this->ge), false); + break; + + case WID_SCMF_CHIN: + this->DrawFaceStringLabel(WID_SCMF_CHIN, GetCompanyManagerFaceBits(this->face, CMFV_CHIN, this->ge), false); + break; + + case WID_SCMF_JACKET: + this->DrawFaceStringLabel(WID_SCMF_JACKET, GetCompanyManagerFaceBits(this->face, CMFV_JACKET, this->ge), false); + break; + + case WID_SCMF_COLLAR: + this->DrawFaceStringLabel(WID_SCMF_COLLAR, GetCompanyManagerFaceBits(this->face, CMFV_COLLAR, this->ge), false); + break; + + case WID_SCMF_FACE: + DrawCompanyManagerFace(this->face, Company::Get((CompanyID)this->window_number)->colour, r.left, r.top); + break; + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + /* Toggle size, advanced/simple face selection */ + case WID_SCMF_TOGGLE_LARGE_SMALL: + case WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON: + this->advanced = !this->advanced; + this->SelectDisplayPlanes(this->advanced); + this->ReInit(); + break; + + /* OK button */ + case WID_SCMF_ACCEPT: + DoCommandP(0, 0, this->face, CMD_SET_COMPANY_MANAGER_FACE); + /* FALL THROUGH */ + + /* Cancel button */ + case WID_SCMF_CANCEL: + delete this; + break; + + /* Load button */ + case WID_SCMF_LOAD: + this->face = _company_manager_face; + ScaleAllCompanyManagerFaceBits(this->face); + ShowErrorMessage(STR_FACE_LOAD_DONE, INVALID_STRING_ID, WL_INFO); + this->UpdateData(); + this->SetDirty(); + break; + + /* 'Company manager face number' button, view and/or set company manager face number */ + case WID_SCMF_FACECODE: + SetDParam(0, this->face); + ShowQueryString(STR_JUST_INT, STR_FACE_FACECODE_CAPTION, 10 + 1, this, CS_NUMERAL, QSF_NONE); + break; + + /* Save button */ + case WID_SCMF_SAVE: + _company_manager_face = this->face; + ShowErrorMessage(STR_FACE_SAVE_DONE, INVALID_STRING_ID, WL_INFO); + break; + + /* Toggle gender (male/female) button */ + case WID_SCMF_MALE: + case WID_SCMF_FEMALE: + case WID_SCMF_MALE2: + case WID_SCMF_FEMALE2: + SetCompanyManagerFaceBits(this->face, CMFV_GENDER, this->ge, (widget == WID_SCMF_FEMALE || widget == WID_SCMF_FEMALE2)); + ScaleAllCompanyManagerFaceBits(this->face); + this->UpdateData(); + this->SetDirty(); + break; + + /* Randomize face button */ + case WID_SCMF_RANDOM_NEW_FACE: + RandomCompanyManagerFaceBits(this->face, this->ge, this->advanced); + this->UpdateData(); + this->SetDirty(); + break; + + /* Toggle ethnicity (european/african) button */ + case WID_SCMF_ETHNICITY_EUR: + case WID_SCMF_ETHNICITY_AFR: + SetCompanyManagerFaceBits(this->face, CMFV_ETHNICITY, this->ge, widget - WID_SCMF_ETHNICITY_EUR); + ScaleAllCompanyManagerFaceBits(this->face); + this->UpdateData(); + this->SetDirty(); + break; + + default: + /* Here all buttons from WID_SCMF_HAS_MOUSTACHE_EARRING to WID_SCMF_GLASSES_R are handled. + * First it checks which CompanyManagerFaceVariable is being changed, and then either + * a: invert the value for boolean variables, or + * b: it checks inside of IncreaseCompanyManagerFaceBits() if a left (_L) butten is pressed and then decrease else increase the variable */ + if (widget >= WID_SCMF_HAS_MOUSTACHE_EARRING && widget <= WID_SCMF_GLASSES_R) { + CompanyManagerFaceVariable cmfv; // which CompanyManagerFaceVariable shall be edited + + if (widget < WID_SCMF_EYECOLOUR_L) { // Bool buttons + switch (widget - WID_SCMF_HAS_MOUSTACHE_EARRING) { + default: NOT_REACHED(); + case 0: cmfv = this->is_female ? CMFV_HAS_TIE_EARRING : CMFV_HAS_MOUSTACHE; break; // Has earring/moustache button + case 1: cmfv = CMFV_HAS_GLASSES; break; // Has glasses button + } + SetCompanyManagerFaceBits(this->face, cmfv, this->ge, !GetCompanyManagerFaceBits(this->face, cmfv, this->ge)); + ScaleAllCompanyManagerFaceBits(this->face); + } else { // Value buttons + switch ((widget - WID_SCMF_EYECOLOUR_L) / 3) { + default: NOT_REACHED(); + case 0: cmfv = CMFV_EYE_COLOUR; break; // Eye colour buttons + case 1: cmfv = CMFV_CHIN; break; // Chin buttons + case 2: cmfv = CMFV_EYEBROWS; break; // Eyebrows buttons + case 3: cmfv = this->is_moust_male ? CMFV_MOUSTACHE : CMFV_LIPS; break; // Moustache or lips buttons + case 4: cmfv = CMFV_NOSE; break; // Nose buttons + case 5: cmfv = CMFV_HAIR; break; // Hair buttons + case 6: cmfv = CMFV_JACKET; break; // Jacket buttons + case 7: cmfv = CMFV_COLLAR; break; // Collar buttons + case 8: cmfv = CMFV_TIE_EARRING; break; // Tie/earring buttons + case 9: cmfv = CMFV_GLASSES; break; // Glasses buttons + } + /* 0 == left (_L), 1 == middle or 2 == right (_R) - button click */ + IncreaseCompanyManagerFaceBits(this->face, cmfv, this->ge, (((widget - WID_SCMF_EYECOLOUR_L) % 3) != 0) ? 1 : -1); + } + this->UpdateData(); + this->SetDirty(); + } + break; + } + } + + virtual void OnQueryTextFinished(char *str) + { + if (str == NULL) return; + /* Set a new company manager face number */ + if (!StrEmpty(str)) { + this->face = strtoul(str, NULL, 10); + ScaleAllCompanyManagerFaceBits(this->face); + ShowErrorMessage(STR_FACE_FACECODE_SET, INVALID_STRING_ID, WL_INFO); + this->UpdateData(); + this->SetDirty(); + } else { + ShowErrorMessage(STR_FACE_FACECODE_ERR, INVALID_STRING_ID, WL_INFO); + } + } +}; + +/** Both text values of parts of the face that depend on the #is_female boolean value. */ +const StringID SelectCompanyManagerFaceWindow::PART_TEXTS_IS_FEMALE[] = { + STR_FACE_MOUSTACHE, STR_FACE_EARRING, // WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT + STR_FACE_TIE, STR_FACE_EARRING, // WID_SCMF_TIE_EARRING_TEXT +}; + +/** Textual names for parts of the face. */ +const StringID SelectCompanyManagerFaceWindow::PART_TEXTS[] = { + STR_FACE_GLASSES, // WID_SCMF_HAS_GLASSES_TEXT + STR_FACE_HAIR, // WID_SCMF_HAIR_TEXT + STR_FACE_EYEBROWS, // WID_SCMF_EYEBROWS_TEXT + STR_FACE_EYECOLOUR, // WID_SCMF_EYECOLOUR_TEXT + STR_FACE_GLASSES, // WID_SCMF_GLASSES_TEXT + STR_FACE_NOSE, // WID_SCMF_NOSE_TEXT + STR_FACE_CHIN, // WID_SCMF_CHIN_TEXT + STR_FACE_JACKET, // WID_SCMF_JACKET_TEXT + STR_FACE_COLLAR, // WID_SCMF_COLLAR_TEXT +}; + +/** Company manager face selection window description */ +static WindowDesc _select_company_manager_face_desc( + WDP_AUTO, "company_face", 0, 0, + WC_COMPANY_MANAGER_FACE, WC_NONE, + WDF_CONSTRUCTION, + _nested_select_company_manager_face_widgets, lengthof(_nested_select_company_manager_face_widgets) +); + +/** + * Open the simple/advanced company manager face selection window + * + * @param parent the parent company window + * @param adv simple or advanced face selection window + * @param top previous top position of the window + * @param left previous left position of the window + */ +static void DoSelectCompanyManagerFace(Window *parent) +{ + if (!Company::IsValidID((CompanyID)parent->window_number)) return; + + if (BringWindowToFrontById(WC_COMPANY_MANAGER_FACE, parent->window_number)) return; + new SelectCompanyManagerFaceWindow(&_select_company_manager_face_desc, parent); +} + +static const NWidgetPart _nested_company_infrastructure_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_CI_CAPTION), SetDataTip(STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_STICKYBOX, COLOUR_GREY), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), + NWidget(NWID_VERTICAL), SetPIP(WD_FRAMERECT_TOP, 4, WD_FRAMETEXT_BOTTOM), + NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2), + NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_RAIL_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0), + NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_RAIL_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1), + EndContainer(), + NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2), + NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_ROAD_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0), + NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_ROAD_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1), + EndContainer(), + NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2), + NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_WATER_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0), + NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_WATER_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1), + EndContainer(), + NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2), + NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_STATION_DESC), SetMinimalTextLines(3, 0), SetFill(1, 0), + NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_STATION_COUNT), SetMinimalTextLines(3, 0), SetFill(0, 1), + EndContainer(), + NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2), + NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_TOTAL_DESC), SetFill(1, 0), + NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_TOTAL), SetFill(0, 1), + EndContainer(), + EndContainer(), + EndContainer(), +}; + +/** + * Window with detailed information about the company's infrastructure. + */ +struct CompanyInfrastructureWindow : Window +{ + RailTypes railtypes; ///< Valid railtypes. + RoadTypes roadtypes; ///< Valid roadtypes. + + uint total_width; ///< String width of the total cost line. + + CompanyInfrastructureWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) + { + this->UpdateRailRoadTypes(); + + this->InitNested(window_number); + this->owner = (Owner)this->window_number; + } + + void UpdateRailRoadTypes() + { + this->railtypes = RAILTYPES_NONE; + this->roadtypes = ROADTYPES_ROAD; // Road is always available. + + /* Find the used railtypes. */ + Engine *e; + FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) { + if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue; + + this->railtypes |= GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes; + } + + /* Get the date introduced railtypes as well. */ + this->railtypes = AddDateIntroducedRailTypes(this->railtypes, MAX_DAY); + + /* Tram is only visible when there will be a tram. */ + FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) { + if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue; + if (!HasBit(e->info.misc_flags, EF_ROAD_TRAM)) continue; + + this->roadtypes |= ROADTYPES_TRAM; + break; + } + } + + /** Get total infrastructure maintenance cost. */ + Money GetTotalMaintenanceCost() const + { + const Company *c = Company::Get((CompanyID)this->window_number); + Money total; + + uint32 rail_total = c->infrastructure.GetRailTotal(); + for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { + if (HasBit(this->railtypes, rt)) total += RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total); + } + total += SignalMaintenanceCost(c->infrastructure.signal); + + if (HasBit(this->roadtypes, ROADTYPE_ROAD)) total += RoadMaintenanceCost(ROADTYPE_ROAD, c->infrastructure.road[ROADTYPE_ROAD]); + if (HasBit(this->roadtypes, ROADTYPE_TRAM)) total += RoadMaintenanceCost(ROADTYPE_TRAM, c->infrastructure.road[ROADTYPE_TRAM]); + + total += CanalMaintenanceCost(c->infrastructure.water); + total += StationMaintenanceCost(c->infrastructure.station); + total += AirportMaintenanceCost(c->index); + + return total; + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_CI_CAPTION: + SetDParam(0, (CompanyID)this->window_number); + break; + } + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + const Company *c = Company::Get((CompanyID)this->window_number); + + switch (widget) { + case WID_CI_RAIL_DESC: { + uint lines = 1; + + size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT).width); + + for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) { + if (HasBit(this->railtypes, rt)) { + lines++; + SetDParam(0, GetRailTypeInfo(rt)->strings.name); + size->width = max(size->width, GetStringBoundingBox(STR_WHITE_STRING).width + WD_FRAMERECT_LEFT); + } + } + if (this->railtypes != RAILTYPES_NONE) { + lines++; + size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS).width + WD_FRAMERECT_LEFT); + } + + size->height = max(size->height, lines * FONT_HEIGHT_NORMAL); + break; + } + + case WID_CI_ROAD_DESC: { + uint lines = 1; + + size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT).width); + + if (HasBit(this->roadtypes, ROADTYPE_ROAD)) { + lines++; + size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD).width + WD_FRAMERECT_LEFT); + } + if (HasBit(this->roadtypes, ROADTYPE_TRAM)) { + lines++; + size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY).width + WD_FRAMERECT_LEFT); + } + + size->height = max(size->height, lines * FONT_HEIGHT_NORMAL); + break; + } + + case WID_CI_WATER_DESC: + size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT).width); + size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS).width + WD_FRAMERECT_LEFT); + break; + + case WID_CI_STATION_DESC: + size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT).width); + size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS).width + WD_FRAMERECT_LEFT); + size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS).width + WD_FRAMERECT_LEFT); + break; + + case WID_CI_RAIL_COUNT: + case WID_CI_ROAD_COUNT: + case WID_CI_WATER_COUNT: + case WID_CI_STATION_COUNT: + case WID_CI_TOTAL: { + /* Find the maximum count that is displayed. */ + uint32 max_val = 1000; // Some random number to reserve enough space. + Money max_cost = 10000; // Some random number to reserve enough space. + uint32 rail_total = c->infrastructure.GetRailTotal(); + for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) { + max_val = max(max_val, c->infrastructure.rail[rt]); + max_cost = max(max_cost, RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total)); + } + max_val = max(max_val, c->infrastructure.signal); + max_cost = max(max_cost, SignalMaintenanceCost(c->infrastructure.signal)); + for (RoadType rt = ROADTYPE_BEGIN; rt < ROADTYPE_END; rt++) { + max_val = max(max_val, c->infrastructure.road[rt]); + max_cost = max(max_cost, RoadMaintenanceCost(rt, c->infrastructure.road[rt])); + } + max_val = max(max_val, c->infrastructure.water); + max_cost = max(max_cost, CanalMaintenanceCost(c->infrastructure.water)); + max_val = max(max_val, c->infrastructure.station); + max_cost = max(max_cost, StationMaintenanceCost(c->infrastructure.station)); + max_val = max(max_val, c->infrastructure.airport); + max_cost = max(max_cost, AirportMaintenanceCost(c->index)); + + SetDParamMaxValue(0, max_val); + uint count_width = GetStringBoundingBox(STR_WHITE_COMMA).width + 20; // Reserve some wiggle room + + if (_settings_game.economy.infrastructure_maintenance) { + SetDParamMaxValue(0, this->GetTotalMaintenanceCost() * 12); // Convert to per year + this->total_width = GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL).width + 20; + size->width = max(size->width, this->total_width); + + SetDParamMaxValue(0, max_cost * 12); // Convert to per year + count_width += max(this->total_width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL).width); + } + + size->width = max(size->width, count_width); + + /* Set height of the total line. */ + if (widget == WID_CI_TOTAL) { + size->height = _settings_game.economy.infrastructure_maintenance ? max(size->height, EXP_LINESPACE + FONT_HEIGHT_NORMAL) : 0; + } + break; + } + } + } + + /** + * Helper for drawing the counts line. + * @param r The bounds to draw in. + * @param y The y position to draw at. + * @param count The count to show on this line. + * @param monthly_cost The monthly costs. + */ + void DrawCountLine(const Rect &r, int &y, int count, Money monthly_cost) const + { + SetDParam(0, count); + DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, STR_WHITE_COMMA, TC_FROMSTRING, SA_RIGHT); + + if (_settings_game.economy.infrastructure_maintenance) { + SetDParam(0, monthly_cost * 12); // Convert to per year + int left = _current_text_dir == TD_RTL ? r.right - this->total_width : r.left; + DrawString(left, left + this->total_width, y, STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL, TC_FROMSTRING, SA_RIGHT); + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + const Company *c = Company::Get((CompanyID)this->window_number); + int y = r.top; + + int offs_left = _current_text_dir == TD_LTR ? WD_FRAMERECT_LEFT : 0; + int offs_right = _current_text_dir == TD_LTR ? 0 : WD_FRAMERECT_LEFT; + + switch (widget) { + case WID_CI_RAIL_DESC: + DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT); + + if (this->railtypes != RAILTYPES_NONE) { + /* Draw name of each valid railtype. */ + RailType rt; + FOR_ALL_SORTED_RAILTYPES(rt) { + if (HasBit(this->railtypes, rt)) { + SetDParam(0, GetRailTypeInfo(rt)->strings.name); + DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_WHITE_STRING); + } + } + DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS); + } else { + /* No valid railtype. */ + DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE); + } + + break; + + case WID_CI_RAIL_COUNT: { + /* Draw infrastructure count for each valid railtype. */ + uint32 rail_total = c->infrastructure.GetRailTotal(); + RailType rt; + FOR_ALL_SORTED_RAILTYPES(rt) { + if (HasBit(this->railtypes, rt)) { + this->DrawCountLine(r, y, c->infrastructure.rail[rt], RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total)); + } + } + if (this->railtypes != RAILTYPES_NONE) { + this->DrawCountLine(r, y, c->infrastructure.signal, SignalMaintenanceCost(c->infrastructure.signal)); + } + break; + } + + case WID_CI_ROAD_DESC: + DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT); + + if (this->roadtypes != ROADTYPES_NONE) { + if (HasBit(this->roadtypes, ROADTYPE_ROAD)) DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD); + if (HasBit(this->roadtypes, ROADTYPE_TRAM)) DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY); + } else { + /* No valid roadtypes. */ + DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE); + } + + break; + + case WID_CI_ROAD_COUNT: + if (HasBit(this->roadtypes, ROADTYPE_ROAD)) { + this->DrawCountLine(r, y, c->infrastructure.road[ROADTYPE_ROAD], RoadMaintenanceCost(ROADTYPE_ROAD, c->infrastructure.road[ROADTYPE_ROAD])); + } + if (HasBit(this->roadtypes, ROADTYPE_TRAM)) { + this->DrawCountLine(r, y, c->infrastructure.road[ROADTYPE_TRAM], RoadMaintenanceCost(ROADTYPE_TRAM, c->infrastructure.road[ROADTYPE_TRAM])); + } + break; + + case WID_CI_WATER_DESC: + DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT); + DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS); + break; + + case WID_CI_WATER_COUNT: + this->DrawCountLine(r, y, c->infrastructure.water, CanalMaintenanceCost(c->infrastructure.water)); + break; + + case WID_CI_TOTAL: + if (_settings_game.economy.infrastructure_maintenance) { + int left = _current_text_dir == TD_RTL ? r.right - this->total_width : r.left; + GfxFillRect(left, y, left + this->total_width, y, PC_WHITE); + y += EXP_LINESPACE; + SetDParam(0, this->GetTotalMaintenanceCost() * 12); // Convert to per year + DrawString(left, left + this->total_width, y, STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL, TC_FROMSTRING, SA_RIGHT); + } + break; + + case WID_CI_STATION_DESC: + DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT); + DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS); + DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS); + break; + + case WID_CI_STATION_COUNT: + this->DrawCountLine(r, y, c->infrastructure.station, StationMaintenanceCost(c->infrastructure.station)); + this->DrawCountLine(r, y, c->infrastructure.airport, AirportMaintenanceCost(c->index)); + break; + } + } + + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (!gui_scope) return; + + this->UpdateRailRoadTypes(); + this->ReInit(); + } +}; + +static WindowDesc _company_infrastructure_desc( + WDP_AUTO, "company_infrastructure", 0, 0, + WC_COMPANY_INFRASTRUCTURE, WC_NONE, + 0, + _nested_company_infrastructure_widgets, lengthof(_nested_company_infrastructure_widgets) +); + +/** + * Open the infrastructure window of a company. + * @param company Company to show infrastructure of. + */ +static void ShowCompanyInfrastructure(CompanyID company) +{ + if (!Company::IsValidID(company)) return; + AllocateWindowDescFront(&_company_infrastructure_desc, company); +} + +static const NWidgetPart _nested_company_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_GREY), + NWidget(WWT_CAPTION, COLOUR_GREY, WID_C_CAPTION), SetDataTip(STR_COMPANY_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_GREY), + NWidget(WWT_STICKYBOX, COLOUR_GREY), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), + NWidget(NWID_HORIZONTAL), SetPIP(4, 6, 4), + NWidget(NWID_VERTICAL), SetPIP(4, 2, 4), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_FACE), SetMinimalSize(92, 119), SetFill(1, 0), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_FACE_TITLE), SetFill(1, 1), SetMinimalTextLines(2, 0), + EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_VERTICAL), SetPIP(4, 5, 5), + NWidget(WWT_TEXT, COLOUR_GREY, WID_C_DESC_INAUGURATION), SetDataTip(STR_COMPANY_VIEW_INAUGURATED_TITLE, STR_NULL), SetFill(1, 0), + NWidget(NWID_HORIZONTAL), SetPIP(0, 5, 0), + NWidget(WWT_LABEL, COLOUR_GREY, WID_C_DESC_COLOUR_SCHEME), SetDataTip(STR_COMPANY_VIEW_COLOUR_SCHEME_TITLE, STR_NULL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_DESC_COLOUR_SCHEME_EXAMPLE), SetMinimalSize(30, 0), SetFill(0, 1), + NWidget(NWID_SPACER), SetFill(1, 0), + EndContainer(), + NWidget(NWID_HORIZONTAL), SetPIP(0, 4, 0), + NWidget(NWID_VERTICAL), + NWidget(WWT_TEXT, COLOUR_GREY, WID_C_DESC_VEHICLE), SetDataTip(STR_COMPANY_VIEW_VEHICLES_TITLE, STR_NULL), + NWidget(NWID_SPACER), SetFill(0, 1), + EndContainer(), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_DESC_VEHICLE_COUNTS), SetMinimalTextLines(4, 0), + NWidget(NWID_SPACER), SetFill(1, 0), + EndContainer(), + EndContainer(), + NWidget(NWID_VERTICAL), SetPIP(4, 2, 4), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_C_SELECT_VIEW_BUILD_HQ), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_VIEW_HQ), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_VIEW_HQ_BUTTON, STR_COMPANY_VIEW_VIEW_HQ_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_C_BUILD_HQ), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_BUILD_HQ_BUTTON, STR_COMPANY_VIEW_BUILD_HQ_TOOLTIP), + EndContainer(), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_C_SELECT_RELOCATE), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_C_RELOCATE_HQ), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_RELOCATE_HQ, STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS), + NWidget(NWID_SPACER), SetMinimalSize(90, 0), + EndContainer(), + NWidget(NWID_SPACER), SetFill(0, 1), + EndContainer(), + EndContainer(), + NWidget(WWT_TEXT, COLOUR_GREY, WID_C_DESC_COMPANY_VALUE), SetDataTip(STR_COMPANY_VIEW_COMPANY_VALUE, STR_NULL), SetFill(1, 0), + NWidget(NWID_VERTICAL), SetPIP(4, 2, 4), + NWidget(NWID_HORIZONTAL), SetPIP(0, 4, 0), + NWidget(NWID_VERTICAL), + NWidget(WWT_TEXT, COLOUR_GREY, WID_C_DESC_INFRASTRUCTURE), SetDataTip(STR_COMPANY_VIEW_INFRASTRUCTURE, STR_NULL), + NWidget(NWID_SPACER), SetFill(0, 1), + EndContainer(), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_DESC_INFRASTRUCTURE_COUNTS), SetMinimalTextLines(5, 0), SetFill(1, 0), + NWidget(NWID_VERTICAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_VIEW_INFRASTRUCTURE), SetDataTip(STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON, STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP), + NWidget(NWID_SPACER), SetFill(0, 1), SetMinimalSize(90, 0), + EndContainer(), + EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_C_SELECT_DESC_OWNERS), + NWidget(NWID_VERTICAL), SetPIP(5, 5, 4), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_DESC_OWNERS), SetMinimalTextLines(3, 0), + NWidget(NWID_SPACER), SetFill(0, 1), + EndContainer(), + EndContainer(), + NWidget(NWID_VERTICAL), SetPIP(4, 2, 4), + NWidget(NWID_SPACER), SetMinimalSize(90, 0), SetFill(0, 1), + /* Multi player buttons. */ + NWidget(NWID_HORIZONTAL), + NWidget(WWT_EMPTY, COLOUR_GREY, WID_C_HAS_PASSWORD), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_C_SELECT_MULTIPLAYER), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_COMPANY_PASSWORD), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_PASSWORD, STR_COMPANY_VIEW_PASSWORD_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_COMPANY_JOIN), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_JOIN, STR_COMPANY_VIEW_JOIN_TOOLTIP), + EndContainer(), + EndContainer(), + EndContainer(), + EndContainer(), + EndContainer(), + EndContainer(), + EndContainer(), + /* Button bars at the bottom. */ + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_C_SELECT_BUTTONS), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_NEW_FACE), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_NEW_FACE_BUTTON, STR_COMPANY_VIEW_NEW_FACE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_COLOUR_SCHEME), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_COLOUR_SCHEME_BUTTON, STR_COMPANY_VIEW_COLOUR_SCHEME_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_PRESIDENT_NAME), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_PRESIDENT_NAME_BUTTON, STR_COMPANY_VIEW_PRESIDENT_NAME_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_COMPANY_NAME), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_COMPANY_NAME_BUTTON, STR_COMPANY_VIEW_COMPANY_NAME_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_BUY_SHARE), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_BUY_SHARE_BUTTON, STR_COMPANY_VIEW_BUY_SHARE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_SELL_SHARE), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_SELL_SHARE_BUTTON, STR_COMPANY_VIEW_SELL_SHARE_TOOLTIP), + EndContainer(), + EndContainer(), +}; + +int GetAmountOwnedBy(const Company *c, Owner owner) +{ + return (c->share_owners[0] == owner) + + (c->share_owners[1] == owner) + + (c->share_owners[2] == owner) + + (c->share_owners[3] == owner); +} + +/** Strings for the company vehicle counts */ +static const StringID _company_view_vehicle_count_strings[] = { + STR_COMPANY_VIEW_TRAINS, STR_COMPANY_VIEW_ROAD_VEHICLES, STR_COMPANY_VIEW_SHIPS, STR_COMPANY_VIEW_AIRCRAFT +}; + +/** + * Window with general information about a company + */ +struct CompanyWindow : Window +{ + CompanyWidgets query_widget; + + /** Display planes in the company window. */ + enum CompanyWindowPlanes { + /* Display planes of the #WID_C_SELECT_MULTIPLAYER selection widget. */ + CWP_MP_C_PWD = 0, ///< Display the company password button. + CWP_MP_C_JOIN, ///< Display the join company button. + + /* Display planes of the #WID_C_SELECT_VIEW_BUILD_HQ selection widget. */ + CWP_VB_VIEW = 0, ///< Display the view button + CWP_VB_BUILD, ///< Display the build button + + /* Display planes of the #WID_C_SELECT_RELOCATE selection widget. */ + CWP_RELOCATE_SHOW = 0, ///< Show the relocate HQ button. + CWP_RELOCATE_HIDE, ///< Hide the relocate HQ button. + + /* Display planes of the #WID_C_SELECT_BUTTONS selection widget. */ + CWP_BUTTONS_LOCAL = 0, ///< Buttons of the local company. + CWP_BUTTONS_OTHER, ///< Buttons of the other companies. + }; + + CompanyWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) + { + this->InitNested(window_number); + this->owner = (Owner)this->window_number; + this->OnInvalidateData(); + } + + virtual void OnPaint() + { + const Company *c = Company::Get((CompanyID)this->window_number); + bool local = this->window_number == _local_company; + + if (!this->IsShaded()) { + bool reinit = false; + + /* Button bar selection. */ + int plane = local ? CWP_BUTTONS_LOCAL : CWP_BUTTONS_OTHER; + NWidgetStacked *wi = this->GetWidget(WID_C_SELECT_BUTTONS); + if (plane != wi->shown_plane) { + wi->SetDisplayedPlane(plane); + this->InvalidateData(); + return; + } + + /* Build HQ button handling. */ + plane = (local && c->location_of_HQ == INVALID_TILE) ? CWP_VB_BUILD : CWP_VB_VIEW; + wi = this->GetWidget(WID_C_SELECT_VIEW_BUILD_HQ); + if (plane != wi->shown_plane) { + wi->SetDisplayedPlane(plane); + this->SetDirty(); + return; + } + + this->SetWidgetDisabledState(WID_C_VIEW_HQ, c->location_of_HQ == INVALID_TILE); + + /* Enable/disable 'Relocate HQ' button. */ + plane = (!local || c->location_of_HQ == INVALID_TILE) ? CWP_RELOCATE_HIDE : CWP_RELOCATE_SHOW; + wi = this->GetWidget(WID_C_SELECT_RELOCATE); + if (plane != wi->shown_plane) { + wi->SetDisplayedPlane(plane); + this->SetDirty(); + return; + } + + /* Owners of company */ + plane = SZSP_HORIZONTAL; + for (uint i = 0; i < lengthof(c->share_owners); i++) { + if (c->share_owners[i] != INVALID_COMPANY) { + plane = 0; + break; + } + } + wi = this->GetWidget(WID_C_SELECT_DESC_OWNERS); + if (plane != wi->shown_plane) { + wi->SetDisplayedPlane(plane); + reinit = true; + } + + /* Multiplayer buttons. */ + plane = ((!_networking) ? (int)SZSP_NONE : (int)(local ? CWP_MP_C_PWD : CWP_MP_C_JOIN)); + wi = this->GetWidget(WID_C_SELECT_MULTIPLAYER); + if (plane != wi->shown_plane) { + wi->SetDisplayedPlane(plane); + reinit = true; + } + this->SetWidgetDisabledState(WID_C_COMPANY_JOIN, c->is_ai); + + if (reinit) { + this->ReInit(); + return; + } + } + + this->DrawWidgets(); + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_C_FACE: { + Dimension face_size = GetSpriteSize(SPR_GRADIENT); + size->width = max(size->width, face_size.width); + size->height = max(size->height, face_size.height); + break; + } + + case WID_C_DESC_COLOUR_SCHEME_EXAMPLE: { + Point offset; + Dimension d = GetSpriteSize(SPR_VEH_BUS_SW_VIEW, &offset); + d.width -= offset.x; + d.height -= offset.y; + *size = maxdim(*size, d); + break; + } + + case WID_C_DESC_COMPANY_VALUE: + SetDParam(0, INT64_MAX); // Arguably the maximum company value + size->width = GetStringBoundingBox(STR_COMPANY_VIEW_COMPANY_VALUE).width; + break; + + case WID_C_DESC_VEHICLE_COUNTS: + SetDParamMaxValue(0, 5000); // Maximum number of vehicles + for (uint i = 0; i < lengthof(_company_view_vehicle_count_strings); i++) { + size->width = max(size->width, GetStringBoundingBox(_company_view_vehicle_count_strings[i]).width); + } + break; + + case WID_C_DESC_INFRASTRUCTURE_COUNTS: + SetDParamMaxValue(0, UINT_MAX); + size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL).width); + size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD).width); + size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_WATER).width); + size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_STATION).width); + size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT).width); + size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_NONE).width); + break; + + case WID_C_DESC_OWNERS: { + const Company *c2; + + FOR_ALL_COMPANIES(c2) { + SetDParamMaxValue(0, 75); + SetDParam(1, c2->index); + + size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_SHARES_OWNED_BY).width); + } + break; + } + +#ifdef ENABLE_NETWORK + case WID_C_HAS_PASSWORD: + *size = maxdim(*size, GetSpriteSize(SPR_LOCK)); + break; +#endif /* ENABLE_NETWORK */ + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + const Company *c = Company::Get((CompanyID)this->window_number); + switch (widget) { + case WID_C_FACE: + DrawCompanyManagerFace(c->face, c->colour, r.left, r.top); + break; + + case WID_C_FACE_TITLE: + SetDParam(0, c->index); + DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE, TC_FROMSTRING, SA_HOR_CENTER); + break; + + case WID_C_DESC_COLOUR_SCHEME_EXAMPLE: { + Point offset; + Dimension d = GetSpriteSize(SPR_VEH_BUS_SW_VIEW, &offset); + d.height -= offset.y; + DrawSprite(SPR_VEH_BUS_SW_VIEW, COMPANY_SPRITE_COLOUR(c->index), r.left - offset.x, (r.top + r.bottom - d.height) / 2 - offset.y); + break; + } + + case WID_C_DESC_VEHICLE_COUNTS: { + uint amounts[4]; + amounts[0] = c->group_all[VEH_TRAIN].num_vehicle; + amounts[1] = c->group_all[VEH_ROAD].num_vehicle; + amounts[2] = c->group_all[VEH_SHIP].num_vehicle; + amounts[3] = c->group_all[VEH_AIRCRAFT].num_vehicle; + + int y = r.top; + if (amounts[0] + amounts[1] + amounts[2] + amounts[3] == 0) { + DrawString(r.left, r.right, y, STR_COMPANY_VIEW_VEHICLES_NONE); + } else { + assert_compile(lengthof(amounts) == lengthof(_company_view_vehicle_count_strings)); + + for (uint i = 0; i < lengthof(amounts); i++) { + if (amounts[i] != 0) { + SetDParam(0, amounts[i]); + DrawString(r.left, r.right, y, _company_view_vehicle_count_strings[i]); + y += FONT_HEIGHT_NORMAL; + } + } + } + break; + } + + case WID_C_DESC_INFRASTRUCTURE_COUNTS: { + uint y = r.top; + + /* Collect rail and road counts. */ + uint rail_pices = c->infrastructure.signal; + uint road_pieces = 0; + for (uint i = 0; i < lengthof(c->infrastructure.rail); i++) rail_pices += c->infrastructure.rail[i]; + for (uint i = 0; i < lengthof(c->infrastructure.road); i++) road_pieces += c->infrastructure.road[i]; + + if (rail_pices == 0 && road_pieces == 0 && c->infrastructure.water == 0 && c->infrastructure.station == 0 && c->infrastructure.airport == 0) { + DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE); + } else { + if (rail_pices != 0) { + SetDParam(0, rail_pices); + DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL); + y += FONT_HEIGHT_NORMAL; + } + if (road_pieces != 0) { + SetDParam(0, road_pieces); + DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD); + y += FONT_HEIGHT_NORMAL; + } + if (c->infrastructure.water != 0) { + SetDParam(0, c->infrastructure.water); + DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_WATER); + y += FONT_HEIGHT_NORMAL; + } + if (c->infrastructure.station != 0) { + SetDParam(0, c->infrastructure.station); + DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_STATION); + y += FONT_HEIGHT_NORMAL; + } + if (c->infrastructure.airport != 0) { + SetDParam(0, c->infrastructure.airport); + DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT); + } + } + + break; + } + + case WID_C_DESC_OWNERS: { + const Company *c2; + uint y = r.top; + + FOR_ALL_COMPANIES(c2) { + uint amt = GetAmountOwnedBy(c, c2->index); + if (amt != 0) { + SetDParam(0, amt * 25); + SetDParam(1, c2->index); + + DrawString(r.left, r.right, y, STR_COMPANY_VIEW_SHARES_OWNED_BY); + y += FONT_HEIGHT_NORMAL; + } + } + break; + } + +#ifdef ENABLE_NETWORK + case WID_C_HAS_PASSWORD: + if (_networking && NetworkCompanyIsPassworded(c->index)) { + DrawSprite(SPR_LOCK, PAL_NONE, r.left, r.top); + } + break; +#endif /* ENABLE_NETWORK */ + } + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_C_CAPTION: + SetDParam(0, (CompanyID)this->window_number); + SetDParam(1, (CompanyID)this->window_number); + break; + + case WID_C_DESC_INAUGURATION: + SetDParam(0, Company::Get((CompanyID)this->window_number)->inaugurated_year); + break; + + case WID_C_DESC_COMPANY_VALUE: + SetDParam(0, CalculateCompanyValue(Company::Get((CompanyID)this->window_number))); + break; + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_C_NEW_FACE: DoSelectCompanyManagerFace(this); break; + + case WID_C_COLOUR_SCHEME: + if (BringWindowToFrontById(WC_COMPANY_COLOUR, this->window_number)) break; + new SelectCompanyLiveryWindow(&_select_company_livery_desc, (CompanyID)this->window_number); + break; + + case WID_C_PRESIDENT_NAME: + this->query_widget = WID_C_PRESIDENT_NAME; + SetDParam(0, this->window_number); + ShowQueryString(STR_PRESIDENT_NAME, STR_COMPANY_VIEW_PRESIDENT_S_NAME_QUERY_CAPTION, MAX_LENGTH_PRESIDENT_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); + break; + + case WID_C_COMPANY_NAME: + this->query_widget = WID_C_COMPANY_NAME; + SetDParam(0, this->window_number); + ShowQueryString(STR_COMPANY_NAME, STR_COMPANY_VIEW_COMPANY_NAME_QUERY_CAPTION, MAX_LENGTH_COMPANY_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); + break; + + case WID_C_VIEW_HQ: { + TileIndex tile = Company::Get((CompanyID)this->window_number)->location_of_HQ; + if (_ctrl_pressed) { + ShowExtraViewPortWindow(tile); + } else { + ScrollMainWindowToTile(tile); + } + break; + } + + case WID_C_BUILD_HQ: + if ((byte)this->window_number != _local_company) return; + if (this->IsWidgetLowered(WID_C_BUILD_HQ)) { + ResetObjectToPlace(); + this->RaiseButtons(); + break; + } + SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, this); + SetTileSelectSize(2, 2); + this->LowerWidget(WID_C_BUILD_HQ); + this->SetWidgetDirty(WID_C_BUILD_HQ); + break; + + case WID_C_RELOCATE_HQ: + if (this->IsWidgetLowered(WID_C_RELOCATE_HQ)) { + ResetObjectToPlace(); + this->RaiseButtons(); + break; + } + SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, this); + SetTileSelectSize(2, 2); + this->LowerWidget(WID_C_RELOCATE_HQ); + this->SetWidgetDirty(WID_C_RELOCATE_HQ); + break; + + case WID_C_VIEW_INFRASTRUCTURE: + ShowCompanyInfrastructure((CompanyID)this->window_number); + break; + + case WID_C_BUY_SHARE: + DoCommandP(0, this->window_number, 0, CMD_BUY_SHARE_IN_COMPANY | CMD_MSG(STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS)); + break; + + case WID_C_SELL_SHARE: + DoCommandP(0, this->window_number, 0, CMD_SELL_SHARE_IN_COMPANY | CMD_MSG(STR_ERROR_CAN_T_SELL_25_SHARE_IN)); + break; + +#ifdef ENABLE_NETWORK + case WID_C_COMPANY_PASSWORD: + if (this->window_number == _local_company) ShowNetworkCompanyPasswordWindow(this); + break; + + case WID_C_COMPANY_JOIN: { + this->query_widget = WID_C_COMPANY_JOIN; + CompanyID company = (CompanyID)this->window_number; + if (_network_server) { + NetworkServerDoMove(CLIENT_ID_SERVER, company); + MarkWholeScreenDirty(); + } else if (NetworkCompanyIsPassworded(company)) { + /* ask for the password */ + ShowQueryString(STR_EMPTY, STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION, NETWORK_PASSWORD_LENGTH, this, CS_ALPHANUMERAL, QSF_NONE); + } else { + /* just send the join command */ + NetworkClientRequestMove(company); + } + break; + } +#endif /* ENABLE_NETWORK */ + } + } + + virtual void OnHundredthTick() + { + /* redraw the window every now and then */ + this->SetDirty(); + } + + virtual void OnPlaceObject(Point pt, TileIndex tile) + { + if (DoCommandP(tile, OBJECT_HQ, 0, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS))) { + ResetObjectToPlace(); + this->RaiseButtons(); + } + } + + virtual void OnPlaceObjectAbort() + { + this->RaiseButtons(); + } + + virtual void OnQueryTextFinished(char *str) + { + if (str == NULL) return; + + switch (this->query_widget) { + default: NOT_REACHED(); + + case WID_C_PRESIDENT_NAME: + DoCommandP(0, 0, 0, CMD_RENAME_PRESIDENT | CMD_MSG(STR_ERROR_CAN_T_CHANGE_PRESIDENT), NULL, str); + break; + + case WID_C_COMPANY_NAME: + DoCommandP(0, 0, 0, CMD_RENAME_COMPANY | CMD_MSG(STR_ERROR_CAN_T_CHANGE_COMPANY_NAME), NULL, str); + break; + +#ifdef ENABLE_NETWORK + case WID_C_COMPANY_JOIN: + NetworkClientRequestMove((CompanyID)this->window_number, str); + break; +#endif /* ENABLE_NETWORK */ + } + } + + + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (this->window_number == _local_company) return; + + if (_settings_game.economy.allow_shares) { // Shares are allowed + const Company *c = Company::Get(this->window_number); + + /* If all shares are owned by someone (none by nobody), disable buy button */ + this->SetWidgetDisabledState(WID_C_BUY_SHARE, GetAmountOwnedBy(c, INVALID_OWNER) == 0 || + /* Only 25% left to buy. If the company is human, disable buying it up.. TODO issues! */ + (GetAmountOwnedBy(c, INVALID_OWNER) == 1 && !c->is_ai) || + /* Spectators cannot do anything of course */ + _local_company == COMPANY_SPECTATOR); + + /* If the company doesn't own any shares, disable sell button */ + this->SetWidgetDisabledState(WID_C_SELL_SHARE, (GetAmountOwnedBy(c, _local_company) == 0) || + /* Spectators cannot do anything of course */ + _local_company == COMPANY_SPECTATOR); + } else { // Shares are not allowed, disable buy/sell buttons + this->DisableWidget(WID_C_BUY_SHARE); + this->DisableWidget(WID_C_SELL_SHARE); + } + } +}; + +static WindowDesc _company_desc( + WDP_AUTO, "company", 0, 0, + WC_COMPANY, WC_NONE, + 0, + _nested_company_widgets, lengthof(_nested_company_widgets) +); + +/** + * Show the window with the overview of the company. + * @param company The company to show the window for. + */ +void ShowCompany(CompanyID company) +{ + if (!Company::IsValidID(company)) return; + + AllocateWindowDescFront(&_company_desc, company); +} + +/** + * Redraw all windows with company infrastructure counts. + * @param company The company to redraw the windows of. + */ +void DirtyCompanyInfrastructureWindows(CompanyID company) +{ + SetWindowDirty(WC_COMPANY, company); + SetWindowDirty(WC_COMPANY_INFRASTRUCTURE, company); +} + +struct BuyCompanyWindow : Window { + BuyCompanyWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) + { + this->InitNested(window_number); + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_BC_FACE: + *size = GetSpriteSize(SPR_GRADIENT); + break; + + case WID_BC_QUESTION: + const Company *c = Company::Get((CompanyID)this->window_number); + SetDParam(0, c->index); + SetDParam(1, c->bankrupt_value); + size->height = GetStringHeight(STR_BUY_COMPANY_MESSAGE, size->width); + break; + } + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_BC_CAPTION: + SetDParam(0, STR_COMPANY_NAME); + SetDParam(1, Company::Get((CompanyID)this->window_number)->index); + break; + } + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + switch (widget) { + case WID_BC_FACE: { + const Company *c = Company::Get((CompanyID)this->window_number); + DrawCompanyManagerFace(c->face, c->colour, r.left, r.top); + break; + } + + case WID_BC_QUESTION: { + const Company *c = Company::Get((CompanyID)this->window_number); + SetDParam(0, c->index); + SetDParam(1, c->bankrupt_value); + DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_BUY_COMPANY_MESSAGE, TC_FROMSTRING, SA_CENTER); + break; + } + } + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_BC_NO: + delete this; + break; + + case WID_BC_YES: + DoCommandP(0, this->window_number, 0, CMD_BUY_COMPANY | CMD_MSG(STR_ERROR_CAN_T_BUY_COMPANY)); + break; + } + } +}; + +static const NWidgetPart _nested_buy_company_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE), + NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE, WID_BC_CAPTION), SetDataTip(STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE), + NWidget(NWID_VERTICAL), SetPIP(8, 8, 8), + NWidget(NWID_HORIZONTAL), SetPIP(8, 10, 8), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_BC_FACE), SetFill(0, 1), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_BC_QUESTION), SetMinimalSize(240, 0), SetFill(1, 1), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(100, 10, 100), + NWidget(WWT_TEXTBTN, COLOUR_LIGHT_BLUE, WID_BC_NO), SetMinimalSize(60, 12), SetDataTip(STR_QUIT_NO, STR_NULL), SetFill(1, 0), + NWidget(WWT_TEXTBTN, COLOUR_LIGHT_BLUE, WID_BC_YES), SetMinimalSize(60, 12), SetDataTip(STR_QUIT_YES, STR_NULL), SetFill(1, 0), + EndContainer(), + EndContainer(), + EndContainer(), +}; + +static WindowDesc _buy_company_desc( + WDP_AUTO, NULL, 0, 0, + WC_BUY_COMPANY, WC_NONE, + WDF_CONSTRUCTION, + _nested_buy_company_widgets, lengthof(_nested_buy_company_widgets) +); + +/** + * Show the query to buy another company. + * @param company The company to buy. + */ +void ShowBuyCompanyDialog(CompanyID company) +{ + AllocateWindowDescFront(&_buy_company_desc, company); +} diff --git a/src/company_gui.h b/src/company_gui.h new file mode 100644 index 0000000..f4964f3 --- /dev/null +++ b/src/company_gui.h @@ -0,0 +1,29 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file company_gui.h GUI Functions related to companies. */ + +#ifndef COMPANY_GUI_H +#define COMPANY_GUI_H + +#include "company_type.h" +#include "gfx_type.h" + +TextColour GetDrawStringCompanyColour(CompanyID company); +void DrawCompanyIcon(CompanyID c, int x, int y); + +void ShowCompanyStations(CompanyID company); +void ShowCompanyFinances(CompanyID company); +void ShowCompany(CompanyID company); + +void InvalidateCompanyWindows(const Company *c); +void DeleteCompanyWindows(CompanyID company); +void DirtyCompanyInfrastructureWindows(CompanyID company); + +#endif /* COMPANY_GUI_H */ diff --git a/src/company_manager_face.h b/src/company_manager_face.h new file mode 100644 index 0000000..993e539 --- /dev/null +++ b/src/company_manager_face.h @@ -0,0 +1,245 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file company_manager_face.h Functionality related to the company manager's face */ + +#ifndef COMPANY_MANAGER_FACE_H +#define COMPANY_MANAGER_FACE_H + +#include "core/random_func.hpp" +#include "core/bitmath_func.hpp" +#include "table/sprites.h" +#include "company_type.h" + +/** The gender/race combinations that we have faces for */ +enum GenderEthnicity { + GENDER_FEMALE = 0, ///< This bit set means a female, otherwise male + ETHNICITY_BLACK = 1, ///< This bit set means black, otherwise white + + GE_WM = 0, ///< A male of Caucasian origin (white) + GE_WF = 1 << GENDER_FEMALE, ///< A female of Caucasian origin (white) + GE_BM = 1 << ETHNICITY_BLACK, ///< A male of African origin (black) + GE_BF = 1 << ETHNICITY_BLACK | 1 << GENDER_FEMALE, ///< A female of African origin (black) + GE_END, +}; +DECLARE_ENUM_AS_BIT_SET(GenderEthnicity) ///< See GenderRace as a bitset + +/** Bitgroups of the CompanyManagerFace variable */ +enum CompanyManagerFaceVariable { + CMFV_GENDER, + CMFV_ETHNICITY, + CMFV_GEN_ETHN, + CMFV_HAS_MOUSTACHE, + CMFV_HAS_TIE_EARRING, + CMFV_HAS_GLASSES, + CMFV_EYE_COLOUR, + CMFV_CHEEKS, + CMFV_CHIN, + CMFV_EYEBROWS, + CMFV_MOUSTACHE, + CMFV_LIPS, + CMFV_NOSE, + CMFV_HAIR, + CMFV_JACKET, + CMFV_COLLAR, + CMFV_TIE_EARRING, + CMFV_GLASSES, + CMFV_END, +}; +DECLARE_POSTFIX_INCREMENT(CompanyManagerFaceVariable) + +/** Information about the valid values of CompanyManagerFace bitgroups as well as the sprites to draw */ +struct CompanyManagerFaceBitsInfo { + byte offset; ///< Offset in bits into the CompanyManagerFace + byte length; ///< Number of bits used in the CompanyManagerFace + byte valid_values[GE_END]; ///< The number of valid values per gender/ethnicity + SpriteID first_sprite[GE_END]; ///< The first sprite per gender/ethnicity +}; + +/** Lookup table for indices into the CompanyManagerFace, valid ranges and sprites */ +static const CompanyManagerFaceBitsInfo _cmf_info[] = { + /* Index off len WM WF BM BF WM WF BM BF + * CMFV_GENDER */ { 0, 1, { 2, 2, 2, 2 }, { 0, 0, 0, 0 } }, ///< 0 = male, 1 = female + /* CMFV_ETHNICITY */ { 1, 2, { 2, 2, 2, 2 }, { 0, 0, 0, 0 } }, ///< 0 = (Western-)Caucasian, 1 = African(-American)/Black + /* CMFV_GEN_ETHN */ { 0, 3, { 4, 4, 4, 4 }, { 0, 0, 0, 0 } }, ///< Shortcut to get/set gender _and_ ethnicity + /* CMFV_HAS_MOUSTACHE */ { 3, 1, { 2, 0, 2, 0 }, { 0, 0, 0, 0 } }, ///< Females do not have a moustache + /* CMFV_HAS_TIE_EARRING */ { 3, 1, { 0, 2, 0, 2 }, { 0, 0, 0, 0 } }, ///< Draw the earring for females or not. For males the tie is always drawn. + /* CMFV_HAS_GLASSES */ { 4, 1, { 2, 2, 2, 2 }, { 0, 0, 0, 0 } }, ///< Whether to draw glasses or not + /* CMFV_EYE_COLOUR */ { 5, 2, { 3, 3, 1, 1 }, { 0, 0, 0, 0 } }, ///< Palette modification + /* CMFV_CHEEKS */ { 0, 0, { 1, 1, 1, 1 }, { 0x325, 0x326, 0x390, 0x3B0 } }, ///< Cheeks are only indexed by their gender/ethnicity + /* CMFV_CHIN */ { 7, 2, { 4, 1, 2, 2 }, { 0x327, 0x327, 0x391, 0x3B1 } }, + /* CMFV_EYEBROWS */ { 9, 4, { 12, 16, 11, 16 }, { 0x32B, 0x337, 0x39A, 0x3B8 } }, + /* CMFV_MOUSTACHE */ { 13, 2, { 3, 0, 3, 0 }, { 0x367, 0, 0x397, 0 } }, ///< Depends on CMFV_HAS_MOUSTACHE + /* CMFV_LIPS */ { 13, 4, { 12, 10, 9, 9 }, { 0x35B, 0x351, 0x3A5, 0x3C8 } }, ///< Depends on !CMFV_HAS_MOUSTACHE + /* CMFV_NOSE */ { 17, 3, { 8, 4, 4, 5 }, { 0x349, 0x34C, 0x393, 0x3B3 } }, ///< Depends on !CMFV_HAS_MOUSTACHE + /* CMFV_HAIR */ { 20, 4, { 9, 5, 5, 4 }, { 0x382, 0x38B, 0x3D4, 0x3D9 } }, + /* CMFV_JACKET */ { 24, 2, { 3, 3, 3, 3 }, { 0x36B, 0x378, 0x36B, 0x378 } }, + /* CMFV_COLLAR */ { 26, 2, { 4, 4, 4, 4 }, { 0x36E, 0x37B, 0x36E, 0x37B } }, + /* CMFV_TIE_EARRING */ { 28, 3, { 6, 3, 6, 3 }, { 0x372, 0x37F, 0x372, 0x3D1 } }, ///< Depends on CMFV_HAS_TIE_EARRING + /* CMFV_GLASSES */ { 31, 1, { 2, 2, 2, 2 }, { 0x347, 0x347, 0x3AE, 0x3AE } } ///< Depends on CMFV_HAS_GLASSES +}; +/** Make sure the table's size is right. */ +assert_compile(lengthof(_cmf_info) == CMFV_END); + +/** + * Gets the company manager's face bits for the given company manager's face variable + * @param cmf the face to extract the bits from + * @param cmfv the face variable to get the data of + * @param ge the gender and ethnicity of the face + * @pre _cmf_info[cmfv].valid_values[ge] != 0 + * @return the requested bits + */ +static inline uint GetCompanyManagerFaceBits(CompanyManagerFace cmf, CompanyManagerFaceVariable cmfv, GenderEthnicity ge) +{ + assert(_cmf_info[cmfv].valid_values[ge] != 0); + + return GB(cmf, _cmf_info[cmfv].offset, _cmf_info[cmfv].length); +} + +/** + * Sets the company manager's face bits for the given company manager's face variable + * @param cmf the face to write the bits to + * @param cmfv the face variable to write the data of + * @param ge the gender and ethnicity of the face + * @param val the new value + * @pre val < _cmf_info[cmfv].valid_values[ge] + */ +static inline void SetCompanyManagerFaceBits(CompanyManagerFace &cmf, CompanyManagerFaceVariable cmfv, GenderEthnicity ge, uint val) +{ + assert(val < _cmf_info[cmfv].valid_values[ge]); + + SB(cmf, _cmf_info[cmfv].offset, _cmf_info[cmfv].length, val); +} + +/** + * Increase/Decrease the company manager's face variable by the given amount. + * If the new value greater than the max value for this variable it will be set to 0. + * Or is it negative (< 0) it will be set to max value. + * + * @param cmf the company manager face to write the bits to + * @param cmfv the company manager face variable to write the data of + * @param ge the gender and ethnicity of the company manager's face + * @param amount the amount which change the value + * + * @pre 0 <= val < _cmf_info[cmfv].valid_values[ge] + */ +static inline void IncreaseCompanyManagerFaceBits(CompanyManagerFace &cmf, CompanyManagerFaceVariable cmfv, GenderEthnicity ge, int8 amount) +{ + int8 val = GetCompanyManagerFaceBits(cmf, cmfv, ge) + amount; // the new value for the cmfv + + /* scales the new value to the correct scope */ + if (val >= _cmf_info[cmfv].valid_values[ge]) { + val = 0; + } else if (val < 0) { + val = _cmf_info[cmfv].valid_values[ge] - 1; + } + + SetCompanyManagerFaceBits(cmf, cmfv, ge, val); // save the new value +} + +/** + * Checks whether the company manager's face bits have a valid range + * @param cmf the face to extract the bits from + * @param cmfv the face variable to get the data of + * @param ge the gender and ethnicity of the face + * @return true if and only if the bits are valid + */ +static inline bool AreCompanyManagerFaceBitsValid(CompanyManagerFace cmf, CompanyManagerFaceVariable cmfv, GenderEthnicity ge) +{ + return GB(cmf, _cmf_info[cmfv].offset, _cmf_info[cmfv].length) < _cmf_info[cmfv].valid_values[ge]; +} + +/** + * Scales a company manager's face bits variable to the correct scope + * @param cmfv the face variable to write the data of + * @param ge the gender and ethnicity of the face + * @param val the to value to scale + * @pre val < (1U << _cmf_info[cmfv].length), i.e. val has a value of 0..2^(bits used for this variable)-1 + * @return the scaled value + */ +static inline uint ScaleCompanyManagerFaceValue(CompanyManagerFaceVariable cmfv, GenderEthnicity ge, uint val) +{ + assert(val < (1U << _cmf_info[cmfv].length)); + + return (val * _cmf_info[cmfv].valid_values[ge]) >> _cmf_info[cmfv].length; +} + +/** + * Scales all company manager's face bits to the correct scope + * + * @param cmf the company manager's face to write the bits to + */ +static inline void ScaleAllCompanyManagerFaceBits(CompanyManagerFace &cmf) +{ + IncreaseCompanyManagerFaceBits(cmf, CMFV_ETHNICITY, GE_WM, 0); // scales the ethnicity + + GenderEthnicity ge = (GenderEthnicity)GB(cmf, _cmf_info[CMFV_GEN_ETHN].offset, _cmf_info[CMFV_GEN_ETHN].length); // gender & ethnicity of the face + + /* Is a male face with moustache. Need to reduce CPU load in the loop. */ + bool is_moust_male = !HasBit(ge, GENDER_FEMALE) && GetCompanyManagerFaceBits(cmf, CMFV_HAS_MOUSTACHE, ge) != 0; + + for (CompanyManagerFaceVariable cmfv = CMFV_EYE_COLOUR; cmfv < CMFV_END; cmfv++) { // scales all other variables + + /* The moustache variable will be scaled only if it is a male face with has a moustache */ + if (cmfv != CMFV_MOUSTACHE || is_moust_male) { + IncreaseCompanyManagerFaceBits(cmf, cmfv, ge, 0); + } + } +} + +/** + * Make a random new face. + * If it is for the advanced company manager's face window then the new face have the same gender + * and ethnicity as the old one, else the gender is equal and the ethnicity is random. + * + * @param cmf the company manager's face to write the bits to + * @param ge the gender and ethnicity of the old company manager's face + * @param adv if it for the advanced company manager's face window + * @param interactive is the call from within the user interface? + * + * @pre scale 'ge' to a valid gender/ethnicity combination + */ +static inline void RandomCompanyManagerFaceBits(CompanyManagerFace &cmf, GenderEthnicity ge, bool adv, bool interactive = true) +{ + /* This method is called from a command when not interactive and + * then we must use Random to get the same result on all clients. */ + cmf = interactive ? InteractiveRandom() : Random(); // random all company manager's face bits + + /* scale ge: 0 == GE_WM, 1 == GE_WF, 2 == GE_BM, 3 == GE_BF (and maybe in future: ...) */ + ge = (GenderEthnicity)((uint)ge % GE_END); + + /* set the gender (and ethnicity) for the new company manager's face */ + if (adv) { + SetCompanyManagerFaceBits(cmf, CMFV_GEN_ETHN, ge, ge); + } else { + SetCompanyManagerFaceBits(cmf, CMFV_GENDER, ge, HasBit(ge, GENDER_FEMALE)); + } + + /* scales all company manager's face bits to the correct scope */ + ScaleAllCompanyManagerFaceBits(cmf); +} + +/** + * Gets the sprite to draw for the given company manager's face variable + * @param cmf the face to extract the data from + * @param cmfv the face variable to get the sprite of + * @param ge the gender and ethnicity of the face + * @pre _cmf_info[cmfv].valid_values[ge] != 0 + * @return sprite to draw + */ +static inline SpriteID GetCompanyManagerFaceSprite(CompanyManagerFace cmf, CompanyManagerFaceVariable cmfv, GenderEthnicity ge) +{ + assert(_cmf_info[cmfv].valid_values[ge] != 0); + + return _cmf_info[cmfv].first_sprite[ge] + GB(cmf, _cmf_info[cmfv].offset, _cmf_info[cmfv].length); +} + +void DrawCompanyManagerFace(CompanyManagerFace face, int colour, int x, int y); + +#endif /* COMPANY_MANAGER_FACE_H */ diff --git a/src/company_type.h b/src/company_type.h new file mode 100644 index 0000000..44a074e --- /dev/null +++ b/src/company_type.h @@ -0,0 +1,67 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file company_type.h Types related to companies. */ + +#ifndef COMPANY_TYPE_H +#define COMPANY_TYPE_H + +#include "core/enum_type.hpp" + +/** + * Enum for all companies/owners. + */ +enum Owner { + /* All companies below MAX_COMPANIES are playable + * companies, above, they are special, computer controlled 'companies' */ + OWNER_BEGIN = 0x00, ///< First owner + COMPANY_FIRST = 0x00, ///< First company, same as owner + MAX_COMPANIES = 0x0F, ///< Maximum number of companies + OWNER_TOWN = 0x0F, ///< A town owns the tile, or a town is expanding + OWNER_NONE = 0x10, ///< The tile has no ownership + OWNER_WATER = 0x11, ///< The tile/execution is done by "water" + OWNER_DEITY = 0x12, ///< The object is owned by a superuser / goal script + OWNER_END, ///< Last + 1 owner + INVALID_OWNER = 0xFF, ///< An invalid owner + INVALID_COMPANY = 0xFF, ///< An invalid company + + /* 'Fake' companies used for networks */ + COMPANY_INACTIVE_CLIENT = 253, ///< The client is joining + COMPANY_NEW_COMPANY = 254, ///< The client wants a new company + COMPANY_SPECTATOR = 255, ///< The client is spectating +}; +DECLARE_POSTFIX_INCREMENT(Owner) + +static const uint MAX_LENGTH_PRESIDENT_NAME_CHARS = 32; ///< The maximum length of a president name in characters including '\0' +static const uint MAX_LENGTH_COMPANY_NAME_CHARS = 32; ///< The maximum length of a company name in characters including '\0' + +static const uint MAX_HISTORY_QUARTERS = 24; ///< The maximum number of quarters kept as performance's history + +/** Define basic enum properties */ +template <> struct EnumPropsT : MakeEnumPropsT {}; +typedef TinyEnumT OwnerByte; + +typedef Owner CompanyID; +typedef OwnerByte CompanyByte; + +typedef uint16 CompanyMask; + +struct Company; +typedef uint32 CompanyManagerFace; ///< Company manager face bits, info see in company_manager_face.h + +/** The reason why the company was removed. */ +enum CompanyRemoveReason { + CRR_MANUAL, ///< The company is manually removed. + CRR_AUTOCLEAN, ///< The company is removed due to autoclean. + CRR_BANKRUPT, ///< The company went belly-up. + + CRR_END, ///< Sentinel for end. +}; + +#endif /* COMPANY_TYPE_H */ diff --git a/src/console.cpp b/src/console.cpp new file mode 100644 index 0000000..5110192 --- /dev/null +++ b/src/console.cpp @@ -0,0 +1,509 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file console.cpp Handling of the in-game console. */ + +#include "stdafx.h" +#include "console_internal.h" +#include "network/network.h" +#include "network/network_func.h" +#include "network/network_admin.h" +#include "debug.h" +#include "console_func.h" +#include "settings_type.h" + +#include + +#include "safeguards.h" + +static const uint ICON_TOKEN_COUNT = 20; ///< Maximum number of tokens in one command + +/* console parser */ +IConsoleCmd *_iconsole_cmds; ///< list of registered commands +IConsoleAlias *_iconsole_aliases; ///< list of registered aliases + +FILE *_iconsole_output_file; + +void IConsoleInit() +{ + _iconsole_output_file = NULL; +#ifdef ENABLE_NETWORK /* Initialize network only variables */ + _redirect_console_to_client = INVALID_CLIENT_ID; + _redirect_console_to_admin = INVALID_ADMIN_ID; +#endif + + IConsoleGUIInit(); + + IConsoleStdLibRegister(); +} + +static void IConsoleWriteToLogFile(const char *string) +{ + if (_iconsole_output_file != NULL) { + /* if there is an console output file ... also print it there */ + const char *header = GetLogPrefix(); + if ((strlen(header) != 0 && fwrite(header, strlen(header), 1, _iconsole_output_file) != 1) || + fwrite(string, strlen(string), 1, _iconsole_output_file) != 1 || + fwrite("\n", 1, 1, _iconsole_output_file) != 1) { + fclose(_iconsole_output_file); + _iconsole_output_file = NULL; + IConsolePrintF(CC_DEFAULT, "cannot write to log file"); + } + } +} + +bool CloseConsoleLogIfActive() +{ + if (_iconsole_output_file != NULL) { + IConsolePrintF(CC_DEFAULT, "file output complete"); + fclose(_iconsole_output_file); + _iconsole_output_file = NULL; + return true; + } + + return false; +} + +void IConsoleFree() +{ + IConsoleGUIFree(); + CloseConsoleLogIfActive(); +} + +/** + * Handle the printing of text entered into the console or redirected there + * by any other means. Text can be redirected to other clients in a network game + * as well as to a logfile. If the network server is a dedicated server, all activities + * are also logged. All lines to print are added to a temporary buffer which can be + * used as a history to print them onscreen + * @param colour_code the colour of the command. Red in case of errors, etc. + * @param string the message entered or output on the console (notice, error, etc.) + */ +void IConsolePrint(TextColour colour_code, const char *string) +{ + assert(IsValidConsoleColour(colour_code)); + + char *str; +#ifdef ENABLE_NETWORK + if (_redirect_console_to_client != INVALID_CLIENT_ID) { + /* Redirect the string to the client */ + NetworkServerSendRcon(_redirect_console_to_client, colour_code, string); + return; + } + + if (_redirect_console_to_admin != INVALID_ADMIN_ID) { + NetworkServerSendAdminRcon(_redirect_console_to_admin, colour_code, string); + return; + } +#endif + + /* Create a copy of the string, strip if of colours and invalid + * characters and (when applicable) assign it to the console buffer */ + str = stredup(string); + str_strip_colours(str); + str_validate(str, str + strlen(str)); + + if (_network_dedicated) { +#ifdef ENABLE_NETWORK + NetworkAdminConsole("console", str); +#endif /* ENABLE_NETWORK */ + fprintf(stdout, "%s%s\n", GetLogPrefix(), str); + fflush(stdout); + IConsoleWriteToLogFile(str); + free(str); // free duplicated string since it's not used anymore + return; + } + + IConsoleWriteToLogFile(str); + IConsoleGUIPrint(colour_code, str); +} + +/** + * Handle the printing of text entered into the console or redirected there + * by any other means. Uses printf() style format, for more information look + * at IConsolePrint() + */ +void CDECL IConsolePrintF(TextColour colour_code, const char *format, ...) +{ + assert(IsValidConsoleColour(colour_code)); + + va_list va; + char buf[ICON_MAX_STREAMSIZE]; + + va_start(va, format); + vseprintf(buf, lastof(buf), format, va); + va_end(va); + + IConsolePrint(colour_code, buf); +} + +/** + * It is possible to print debugging information to the console, + * which is achieved by using this function. Can only be used by + * debug() in debug.cpp. You need at least a level 2 (developer) for debugging + * messages to show up + * @param dbg debugging category + * @param string debugging message + */ +void IConsoleDebug(const char *dbg, const char *string) +{ + if (_settings_client.gui.developer <= 1) return; + IConsolePrintF(CC_DEBUG, "dbg: [%s] %s", dbg, string); +} + +/** + * It is possible to print warnings to the console. These are mostly + * errors or mishaps, but non-fatal. You need at least a level 1 (developer) for + * debugging messages to show up + */ +void IConsoleWarning(const char *string) +{ + if (_settings_client.gui.developer == 0) return; + IConsolePrintF(CC_WARNING, "WARNING: %s", string); +} + +/** + * It is possible to print error information to the console. This can include + * game errors, or errors in general you would want the user to notice + */ +void IConsoleError(const char *string) +{ + IConsolePrintF(CC_ERROR, "ERROR: %s", string); +} + +/** + * Change a string into its number representation. Supports + * decimal and hexadecimal numbers as well as 'on'/'off' 'true'/'false' + * @param *value the variable a successful conversion will be put in + * @param *arg the string to be converted + * @return Return true on success or false on failure + */ +bool GetArgumentInteger(uint32 *value, const char *arg) +{ + char *endptr; + + if (strcmp(arg, "on") == 0 || strcmp(arg, "true") == 0) { + *value = 1; + return true; + } + if (strcmp(arg, "off") == 0 || strcmp(arg, "false") == 0) { + *value = 0; + return true; + } + + *value = strtoul(arg, &endptr, 0); + return arg != endptr; +} + +/** + * Add an item to an alphabetically sorted list. + * @param base first item of the list + * @param item_new the item to add + */ +template +void IConsoleAddSorted(T **base, T *item_new) +{ + if (*base == NULL) { + *base = item_new; + return; + } + + T *item_before = NULL; + T *item = *base; + /* The list is alphabetically sorted, insert the new item at the correct location */ + while (item != NULL) { + if (strcmp(item->name, item_new->name) > 0) break; // insert here + + item_before = item; + item = item->next; + } + + if (item_before == NULL) { + *base = item_new; + } else { + item_before->next = item_new; + } + + item_new->next = item; +} + +/** + * Remove underscores from a string; the string will be modified! + * @param name The string to remove the underscores from. + * @return #name. + */ +char *RemoveUnderscores(char *name) +{ + char *q = name; + for (const char *p = name; *p != '\0'; p++) { + if (*p != '_') *q++ = *p; + } + *q = '\0'; + return name; +} + +/** + * Register a new command to be used in the console + * @param name name of the command that will be used + * @param proc function that will be called upon execution of command + */ +void IConsoleCmdRegister(const char *name, IConsoleCmdProc *proc, IConsoleHook *hook) +{ + IConsoleCmd *item_new = MallocT(1); + item_new->name = RemoveUnderscores(stredup(name)); + item_new->next = NULL; + item_new->proc = proc; + item_new->hook = hook; + + IConsoleAddSorted(&_iconsole_cmds, item_new); +} + +/** + * Find the command pointed to by its string + * @param name command to be found + * @return return Cmdstruct of the found command, or NULL on failure + */ +IConsoleCmd *IConsoleCmdGet(const char *name) +{ + IConsoleCmd *item; + + for (item = _iconsole_cmds; item != NULL; item = item->next) { + if (strcmp(item->name, name) == 0) return item; + } + return NULL; +} + +/** + * Register a an alias for an already existing command in the console + * @param name name of the alias that will be used + * @param cmd name of the command that 'name' will be alias of + */ +void IConsoleAliasRegister(const char *name, const char *cmd) +{ + if (IConsoleAliasGet(name) != NULL) { + IConsoleError("an alias with this name already exists; insertion aborted"); + return; + } + + char *new_alias = RemoveUnderscores(stredup(name)); + char *cmd_aliased = stredup(cmd); + IConsoleAlias *item_new = MallocT(1); + + item_new->next = NULL; + item_new->cmdline = cmd_aliased; + item_new->name = new_alias; + + IConsoleAddSorted(&_iconsole_aliases, item_new); +} + +/** + * Find the alias pointed to by its string + * @param name alias to be found + * @return return Aliasstruct of the found alias, or NULL on failure + */ +IConsoleAlias *IConsoleAliasGet(const char *name) +{ + IConsoleAlias *item; + + for (item = _iconsole_aliases; item != NULL; item = item->next) { + if (strcmp(item->name, name) == 0) return item; + } + + return NULL; +} +/** + * An alias is just another name for a command, or for more commands + * Execute it as well. + * @param *alias is the alias of the command + * @param tokencount the number of parameters passed + * @param *tokens are the parameters given to the original command (0 is the first param) + */ +static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char *tokens[ICON_TOKEN_COUNT]) +{ + char alias_buffer[ICON_MAX_STREAMSIZE] = { '\0' }; + char *alias_stream = alias_buffer; + + DEBUG(console, 6, "Requested command is an alias; parsing..."); + + for (const char *cmdptr = alias->cmdline; *cmdptr != '\0'; cmdptr++) { + switch (*cmdptr) { + case '\'': // ' will double for "" + alias_stream = strecpy(alias_stream, "\"", lastof(alias_buffer)); + break; + + case ';': // Cmd separator; execute previous and start new command + IConsoleCmdExec(alias_buffer); + + alias_stream = alias_buffer; + *alias_stream = '\0'; // Make sure the new command is terminated. + + cmdptr++; + break; + + case '%': // Some or all parameters + cmdptr++; + switch (*cmdptr) { + case '+': { // All parameters separated: "[param 1]" "[param 2]" + for (uint i = 0; i != tokencount; i++) { + if (i != 0) alias_stream = strecpy(alias_stream, " ", lastof(alias_buffer)); + alias_stream = strecpy(alias_stream, "\"", lastof(alias_buffer)); + alias_stream = strecpy(alias_stream, tokens[i], lastof(alias_buffer)); + alias_stream = strecpy(alias_stream, "\"", lastof(alias_buffer)); + } + break; + } + + case '!': { // Merge the parameters to one: "[param 1] [param 2] [param 3...]" + alias_stream = strecpy(alias_stream, "\"", lastof(alias_buffer)); + for (uint i = 0; i != tokencount; i++) { + if (i != 0) alias_stream = strecpy(alias_stream, " ", lastof(alias_buffer)); + alias_stream = strecpy(alias_stream, tokens[i], lastof(alias_buffer)); + } + alias_stream = strecpy(alias_stream, "\"", lastof(alias_buffer)); + break; + } + + default: { // One specific parameter: %A = [param 1] %B = [param 2] ... + int param = *cmdptr - 'A'; + + if (param < 0 || param >= tokencount) { + IConsoleError("too many or wrong amount of parameters passed to alias, aborting"); + IConsolePrintF(CC_WARNING, "Usage of alias '%s': %s", alias->name, alias->cmdline); + return; + } + + alias_stream = strecpy(alias_stream, "\"", lastof(alias_buffer)); + alias_stream = strecpy(alias_stream, tokens[param], lastof(alias_buffer)); + alias_stream = strecpy(alias_stream, "\"", lastof(alias_buffer)); + break; + } + } + break; + + default: + *alias_stream++ = *cmdptr; + *alias_stream = '\0'; + break; + } + + if (alias_stream >= lastof(alias_buffer) - 1) { + IConsoleError("Requested alias execution would overflow execution buffer"); + return; + } + } + + IConsoleCmdExec(alias_buffer); +} + +/** + * Execute a given command passed to us. First chop it up into + * individual tokens (separated by spaces), then execute it if possible + * @param cmdstr string to be parsed and executed + */ +void IConsoleCmdExec(const char *cmdstr) +{ + const char *cmdptr; + char *tokens[ICON_TOKEN_COUNT], tokenstream[ICON_MAX_STREAMSIZE]; + uint t_index, tstream_i; + + bool longtoken = false; + bool foundtoken = false; + + if (cmdstr[0] == '#') return; // comments + + for (cmdptr = cmdstr; *cmdptr != '\0'; cmdptr++) { + if (!IsValidChar(*cmdptr, CS_ALPHANUMERAL)) { + IConsoleError("command contains malformed characters, aborting"); + IConsolePrintF(CC_ERROR, "ERROR: command was: '%s'", cmdstr); + return; + } + } + + DEBUG(console, 4, "Executing cmdline: '%s'", cmdstr); + + memset(&tokens, 0, sizeof(tokens)); + memset(&tokenstream, 0, sizeof(tokenstream)); + + /* 1. Split up commandline into tokens, separated by spaces, commands + * enclosed in "" are taken as one token. We can only go as far as the amount + * of characters in our stream or the max amount of tokens we can handle */ + for (cmdptr = cmdstr, t_index = 0, tstream_i = 0; *cmdptr != '\0'; cmdptr++) { + if (t_index >= lengthof(tokens) || tstream_i >= lengthof(tokenstream)) break; + + switch (*cmdptr) { + case ' ': // Token separator + if (!foundtoken) break; + + if (longtoken) { + tokenstream[tstream_i] = *cmdptr; + } else { + tokenstream[tstream_i] = '\0'; + foundtoken = false; + } + + tstream_i++; + break; + case '"': // Tokens enclosed in "" are one token + longtoken = !longtoken; + if (!foundtoken) { + tokens[t_index++] = &tokenstream[tstream_i]; + foundtoken = true; + } + break; + case '\\': // Escape character for "" + if (cmdptr[1] == '"' && tstream_i + 1 < lengthof(tokenstream)) { + tokenstream[tstream_i++] = *++cmdptr; + break; + } + /* FALL THROUGH */ + default: // Normal character + tokenstream[tstream_i++] = *cmdptr; + + if (!foundtoken) { + tokens[t_index++] = &tokenstream[tstream_i - 1]; + foundtoken = true; + } + break; + } + } + + for (uint i = 0; tokens[i] != NULL; i++) { + DEBUG(console, 8, "Token %d is: '%s'", i, tokens[i]); + } + + if (StrEmpty(tokens[0])) return; // don't execute empty commands + /* 2. Determine type of command (cmd or alias) and execute + * First try commands, then aliases. Execute + * the found action taking into account its hooking code + */ + RemoveUnderscores(tokens[0]); + IConsoleCmd *cmd = IConsoleCmdGet(tokens[0]); + if (cmd != NULL) { + ConsoleHookResult chr = (cmd->hook == NULL ? CHR_ALLOW : cmd->hook(true)); + switch (chr) { + case CHR_ALLOW: + if (!cmd->proc(t_index, tokens)) { // index started with 0 + cmd->proc(0, NULL); // if command failed, give help + } + return; + + case CHR_DISALLOW: return; + case CHR_HIDE: break; + } + } + + t_index--; + IConsoleAlias *alias = IConsoleAliasGet(tokens[0]); + if (alias != NULL) { + IConsoleAliasExec(alias, t_index, &tokens[1]); + return; + } + + IConsoleError("command not found"); +} diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp new file mode 100644 index 0000000..8d9e041 --- /dev/null +++ b/src/console_cmds.cpp @@ -0,0 +1,2031 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD 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, version 2. + * OpenTTD 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 OpenTTD. If not, see . + */ + +/** @file console_cmds.cpp Implementation of the console hooks. */ + +#include "stdafx.h" +#include "console_internal.h" +#include "debug.h" +#include "engine_func.h" +#include "landscape.h" +#include "saveload/saveload.h" +#include "network/network.h" +#include "network/network_func.h" +#include "network/network_base.h" +#include "network/network_admin.h" +#include "network/network_client.h" +#include "command_func.h" +#include "settings_func.h" +#include "fios.h" +#include "fileio_func.h" +#include "screenshot.h" +#include "genworld.h" +#include "strings_func.h" +#include "viewport_func.h" +#include "window_func.h" +#include "date_func.h" +#include "company_func.h" +#include "gamelog.h" +#include "ai/ai.hpp" +#include "ai/ai_config.hpp" +#include "newgrf.h" +#include "console_func.h" +#include "engine_base.h" +#include "game/game.hpp" +#include "table/strings.h" + +#include "safeguards.h" + +/* scriptfile handling */ +static bool _script_running; ///< Script is running (used to abort execution when #ConReturn is encountered). + +/* console command defines */ +#define DEF_CONSOLE_CMD(function) static bool function(byte argc, char *argv[]) +#define DEF_CONSOLE_HOOK(function) static ConsoleHookResult function(bool echo) + + +/**************** + * command hooks + ****************/ + +#ifdef ENABLE_NETWORK + +/** + * Check network availability and inform in console about failure of detection. + * @return Network availability. + */ +static inline bool NetworkAvailable(bool echo) +{ + if (!_network_available) { + if (echo) IConsoleError("You cannot use this command because there is no network available."); + return false; + } + return true; +} + +/** + * Check whether we are a server. + * @return Are we a server? True when yes, false otherwise. + */ +DEF_CONSOLE_HOOK(ConHookServerOnly) +{ + if (!NetworkAvailable(echo)) return CHR_DISALLOW; + + if (!_network_server) { + if (echo) IConsoleError("This command is only available to a network server."); + return CHR_DISALLOW; + } + return CHR_ALLOW; +} + +/** + * Check whether we are a client in a network game. + * @return Are we a client in a network game? True when yes, false otherwise. + */ +DEF_CONSOLE_HOOK(ConHookClientOnly) +{ + if (!NetworkAvailable(echo)) return CHR_DISALLOW; + + if (_network_server) { + if (echo) IConsoleError("This command is not available to a network server."); + return CHR_DISALLOW; + } + return CHR_ALLOW; +} + +/** + * Check whether we are in a multiplayer game. + * @return True when we are client or server in a network game. + */ +DEF_CONSOLE_HOOK(ConHookNeedNetwork) +{ + if (!NetworkAvailable(echo)) return CHR_DISALLOW; + + if (!_networking || (!_network_server && !MyClient::IsConnected())) { + if (echo) IConsoleError("Not connected. This command is only available in multiplayer."); + return CHR_DISALLOW; + } + return CHR_ALLOW; +} + +/** + * Check whether we are in single player mode. + * @return True when no network is active. + */ +DEF_CONSOLE_HOOK(ConHookNoNetwork) +{ + if (_networking) { + if (echo) IConsoleError("This command is forbidden in multiplayer."); + return CHR_DISALLOW; + } + return CHR_ALLOW; +} + +#else +# define ConHookNoNetwork NULL +#endif /* ENABLE_NETWORK */ + +DEF_CONSOLE_HOOK(ConHookNewGRFDeveloperTool) +{ + if (_settings_client.gui.newgrf_developer_tools) { + if (_game_mode == GM_MENU) { + if (echo) IConsoleError("This command is only available in game and editor."); + return CHR_DISALLOW; + } +#ifdef ENABLE_NETWORK + return ConHookNoNetwork(echo); +#else + return CHR_ALLOW; +#endif + } + return CHR_HIDE; +} + +/** + * Show help for the console. + * @param str String to print in the console. + */ +static void IConsoleHelp(const char *str) +{ + IConsolePrintF(CC_WARNING, "- %s", str); +} + +/** + * Reset status of all engines. + * @return Will always succeed. + */ +DEF_CONSOLE_CMD(ConResetEngines) +{ + if (argc == 0) { + IConsoleHelp("Reset status data of all engines. This might solve some issues with 'lost' engines. Usage: 'resetengines'"); + return true; + } + + StartupEngines(); + return true; +} + +/** + * Reset status of the engine pool. + * @return Will always return true. + * @note Resetting the pool only succeeds when there are no vehicles ingame. + */ +DEF_CONSOLE_CMD(ConResetEnginePool) +{ + if (argc == 0) { + IConsoleHelp("Reset NewGRF allocations of engine slots. This will remove invalid engine definitions, and might make default engines available again."); + return true; + } + + if (_game_mode == GM_MENU) { + IConsoleError("This command is only available in game and editor."); + return true; + } + + if (!EngineOverrideManager::ResetToCurrentNewGRFConfig()) { + IConsoleError("This can only be done when there are no vehicles in the game."); + return true; + } + + return true; +} + +#ifdef _DEBUG +/** + * Reset a tile to bare land in debug mode. + * param tile number. + * @return True when the tile is reset or the help on usage was printed (0 or two parameters). + */ +DEF_CONSOLE_CMD(ConResetTile) +{ + if (argc == 0) { + IConsoleHelp("Reset a tile to bare land. Usage: 'resettile '"); + IConsoleHelp("Tile can be either decimal (34161) or hexadecimal (0x4a5B)"); + return true; + } + + if (argc == 2) { + uint32 result; + if (GetArgumentInteger(&result, argv[1])) { + DoClearSquare((TileIndex)result); + return true; + } + } + + return false; +} +#endif /* _DEBUG */ + +/** + * Scroll to a tile on the map. + * @param arg1 tile tile number or tile x coordinate. + * @param arg2 optionally tile y coordinate. + * @note When only one argument is given it is intepreted as the tile number. + * When two arguments are given, they are interpreted as the tile's x + * and y coordinates. + * @return True when either console help was shown or a proper amount of parameters given. + */ +DEF_CONSOLE_CMD(ConScrollToTile) +{ + switch (argc) { + case 0: + IConsoleHelp("Center the screen on a given tile."); + IConsoleHelp("Usage: 'scrollto ' or 'scrollto '"); + IConsoleHelp("Numbers can be either decimal (34161) or hexadecimal (0x4a5B)."); + return true; + + case 2: { + uint32 result; + if (GetArgumentInteger(&result, argv[1])) { + if (result >= MapSize()) { + IConsolePrint(CC_ERROR, "Tile does not exist"); + return true; + } + ScrollMainWindowToTile((TileIndex)result); + return true; + } + break; + } + + case 3: { + uint32 x, y; + if (GetArgumentInteger(&x, argv[1]) && GetArgumentInteger(&y, argv[2])) { + if (x >= MapSizeX() || y >= MapSizeY()) { + IConsolePrint(CC_ERROR, "Tile does not exist"); + return true; + } + ScrollMainWindowToTile(TileXY(x, y)); + return true; + } + break; + } + } + + return false; +} + +/** + * Save the map to a file. + * @param filename the filename to save the map to. + * @return True when help was displayed or the file attempted to be saved. + */ +DEF_CONSOLE_CMD(ConSave) +{ + if (argc == 0) { + IConsoleHelp("Save the current game. Usage: 'save '"); + return true; + } + + if (argc == 2) { + char *filename = str_fmt("%s.sav", argv[1]); + IConsolePrint(CC_DEFAULT, "Saving map..."); + + if (SaveOrLoad(filename, SL_SAVE, SAVE_DIR) != SL_OK) { + IConsolePrint(CC_ERROR, "Saving map failed"); + } else { + IConsolePrintF(CC_DEFAULT, "Map successfully saved to %s", filename); + } + free(filename); + return true; + } + + return false; +} + +/** + * Explicitly save the configuration. + * @return True. + */ +DEF_CONSOLE_CMD(ConSaveConfig) +{ + if (argc == 0) { + IConsoleHelp("Saves the configuration for new games to the configuration file, typically 'openttd.cfg'."); + IConsoleHelp("It does not save the configuration of the current game to the configuration file."); + return true; + } + + SaveToConfig(); + IConsolePrint(CC_DEFAULT, "Saved config."); + return true; +} + +/** + * Get savegame file informations. + * @param file The savegame filename to return information about. Can be the actual name + * or a numbered entry into the filename list. + * @return FiosItem The information on the file. + */ +static const FiosItem *GetFiosItem(const char *file) +{ + _saveload_mode = SLD_LOAD_GAME; + BuildFileList(); + + for (const FiosItem *item = _fios_items.Begin(); item != _fios_items.End(); item++) { + if (strcmp(file, item->name) == 0) return item; + if (strcmp(file, item->title) == 0) return item; + } + + /* If no name matches, try to parse it as number */ + char *endptr; + int i = strtol(file, &endptr, 10); + if (file == endptr || *endptr != '\0') i = -1; + + if (IsInsideMM(i, 0, _fios_items.Length())) return _fios_items.Get(i); + + /* As a last effort assume it is an OpenTTD savegame and + * that the ".sav" part was not given. */ + char long_file[MAX_PATH]; + seprintf(long_file, lastof(long_file), "%s.sav", file); + for (const FiosItem *item = _fios_items.Begin(); item != _fios_items.End(); item++) { + if (strcmp(long_file, item->name) == 0) return item; + if (strcmp(long_file, item->title) == 0) return item; + } + + return NULL; +} + + +DEF_CONSOLE_CMD(ConLoad) +{ + if (argc == 0) { + IConsoleHelp("Load a game by name or index. Usage: 'load '"); + return true; + } + + if (argc != 2) return false; + + const char *file = argv[1]; + const FiosItem *item = GetFiosItem(file); + if (item != NULL) { + switch (item->type) { + case FIOS_TYPE_FILE: case FIOS_TYPE_OLDFILE: { + _switch_mode = SM_LOAD_GAME; + SetFiosType(item->type); + + strecpy(_file_to_saveload.name, FiosBrowseTo(item), lastof(_file_to_saveload.name)); + strecpy(_file_to_saveload.title, item->title, lastof(_file_to_saveload.title)); + break; + } + default: IConsolePrintF(CC_ERROR, "%s: Not a savegame.", file); + } + } else { + IConsolePrintF(CC_ERROR, "%s: No such file or directory.", file); + } + + FiosFreeSavegameList(); + return true; +} + + +DEF_CONSOLE_CMD(ConRemove) +{ + if (argc == 0) { + IConsoleHelp("Remove a savegame by name or index. Usage: 'rm '"); + return true; + } + + if (argc != 2) return false; + + const char *file = argv[1]; + const FiosItem *item = GetFiosItem(file); + if (item != NULL) { + if (!FiosDelete(item->name)) { + IConsolePrintF(CC_ERROR, "%s: Failed to delete file", file); + } + } else { + IConsolePrintF(CC_ERROR, "%s: No such file or directory.", file); + } + + FiosFreeSavegameList(); + return true; +} + + +/* List all the files in the current dir via console */ +DEF_CONSOLE_CMD(ConListFiles) +{ + if (argc == 0) { + IConsoleHelp("List all loadable savegames and directories in the current dir via console. Usage: 'ls | dir'"); + return true; + } + + BuildFileList(); + + for (uint i = 0; i < _fios_items.Length(); i++) { + IConsolePrintF(CC_DEFAULT, "%d) %s", i, _fios_items[i].title); + } + + FiosFreeSavegameList(); + return true; +} + +/* Change the dir via console */ +DEF_CONSOLE_CMD(ConChangeDirectory) +{ + if (argc == 0) { + IConsoleHelp("Change the dir via console. Usage: 'cd '"); + return true; + } + + if (argc != 2) return false; + + const char *file = argv[1]; + const FiosItem *item = GetFiosItem(file); + if (item != NULL) { + switch (item->type) { + case FIOS_TYPE_DIR: case FIOS_TYPE_DRIVE: case FIOS_TYPE_PARENT: + FiosBrowseTo(item); + break; + default: IConsolePrintF(CC_ERROR, "%s: Not a directory.", file); + } + } else { + IConsolePrintF(CC_ERROR, "%s: No such file or directory.", file); + } + + FiosFreeSavegameList(); + return true; +} + +DEF_CONSOLE_CMD(ConPrintWorkingDirectory) +{ + const char *path; + + if (argc == 0) { + IConsoleHelp("Print out the current working directory. Usage: 'pwd'"); + return true; + } + + /* XXX - Workaround for broken file handling */ + FiosGetSavegameList(SLD_LOAD_GAME); + FiosFreeSavegameList(); + + FiosGetDescText(&path, NULL); + IConsolePrint(CC_DEFAULT, path); + return true; +} + +DEF_CONSOLE_CMD(ConClearBuffer) +{ + if (argc == 0) { + IConsoleHelp("Clear the console buffer. Usage: 'clear'"); + return true; + } + + IConsoleClearBuffer(); + SetWindowDirty(WC_CONSOLE, 0); + return true; +} + + +/********************************** + * Network Core Console Commands + **********************************/ +#ifdef ENABLE_NETWORK + +static bool ConKickOrBan(const char *argv, bool ban) +{ + uint n; + + if (strchr(argv, '.') == NULL && strchr(argv, ':') == NULL) { // banning with ID + ClientID client_id = (ClientID)atoi(argv); + + /* Don't kill the server, or the client doing the rcon. The latter can't be kicked because + * kicking frees closes and subsequently free the connection related instances, which we + * would be reading from and writing to after returning. So we would read or write data + * from freed memory up till the segfault triggers. */ + if (client_id == CLIENT_ID_SERVER || client_id == _redirect_console_to_client) { + IConsolePrintF(CC_ERROR, "ERROR: Silly boy, you can not %s yourself!", ban ? "ban" : "kick"); + return true; + } + + NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id); + if (ci == NULL) { + IConsoleError("Invalid client"); + return true; + } + + if (!ban) { + /* Kick only this client, not all clients with that IP */ + NetworkServerKickClient(client_id); + return true; + } + + /* When banning, kick+ban all clients with that IP */ + n = NetworkServerKickOrBanIP(client_id, ban); + } else { + n = NetworkServerKickOrBanIP(argv, ban); + } + + if (n == 0) { + IConsolePrint(CC_DEFAULT, ban ? "Client not online, address added to banlist" : "Client not found"); + } else { + IConsolePrintF(CC_DEFAULT, "%sed %u client(s)", ban ? "Bann" : "Kick", n); + } + + return true; +} + +DEF_CONSOLE_CMD(ConKick) +{ + if (argc == 0) { + IConsoleHelp("Kick a client from a network game. Usage: 'kick '"); + IConsoleHelp("For client-id's, see the command 'clients'"); + return true; + } + + if (argc != 2) return false; + + return ConKickOrBan(argv[1], false); +} + +DEF_CONSOLE_CMD(ConBan) +{ + if (argc == 0) { + IConsoleHelp("Ban a client from a network game. Usage: 'ban '"); + IConsoleHelp("For client-id's, see the command 'clients'"); + IConsoleHelp("If the client is no longer online, you can still ban his/her IP"); + return true; + } + + if (argc != 2) return false; + + return ConKickOrBan(argv[1], true); +} + +DEF_CONSOLE_CMD(ConUnBan) +{ + + if (argc == 0) { + IConsoleHelp("Unban a client from a network game. Usage: 'unban '"); + IConsoleHelp("For a list of banned IP's, see the command 'banlist'"); + return true; + } + + if (argc != 2) return false; + + uint index = (strchr(argv[1], '.') == NULL) ? atoi(argv[1]) : 0; + index--; + uint i = 0; + + for (char **iter = _network_ban_list.Begin(); iter != _network_ban_list.End(); iter++, i++) { + if (strcmp(_network_ban_list[i], argv[1]) == 0 || index == i) { + free(_network_ban_list[i]); + _network_ban_list.Erase(iter); + IConsolePrint(CC_DEFAULT, "IP unbanned."); + return true; + } + } + + IConsolePrint(CC_DEFAULT, "IP not in ban-list."); + return true; +} + +DEF_CONSOLE_CMD(ConBanList) +{ + if (argc == 0) { + IConsoleHelp("List the IP's of banned clients: Usage 'banlist'"); + return true; + } + + IConsolePrint(CC_DEFAULT, "Banlist: "); + + uint i = 1; + for (char **iter = _network_ban_list.Begin(); iter != _network_ban_list.End(); iter++, i++) { + IConsolePrintF(CC_DEFAULT, " %d) %s", i, *iter); + } + + return true; +} + +DEF_CONSOLE_CMD(ConPauseGame) +{ + if (argc == 0) { + IConsoleHelp("Pause a network game. Usage: 'pause'"); + return true; + } + + if ((_pause_mode & PM_PAUSED_NORMAL) == PM_UNPAUSED) { + DoCommandP(0, PM_PAUSED_NORMAL, 1, CMD_PAUSE); + if (!_networking) IConsolePrint(CC_DEFAULT, "Game paused."); + } else { + IConsolePrint(CC_DEFAULT, "Game is already paused."); + } + + return true; +} + +DEF_CONSOLE_CMD(ConUnpauseGame) +{ + if (argc == 0) { + IConsoleHelp("Unpause a network game. Usage: 'unpause'"); + return true; + } + + if ((_pause_mode & PM_PAUSED_NORMAL) != PM_UNPAUSED) { + DoCommandP(0, PM_PAUSED_NORMAL, 0, CMD_PAUSE); + if (!_networking) IConsolePrint(CC_DEFAULT, "Game unpaused."); + } else if ((_pause_mode & PM_PAUSED_ERROR) != PM_UNPAUSED) { + IConsolePrint(CC_DEFAULT, "Game is in error state and cannot be unpaused via console."); + } else if (_pause_mode != PM_UNPAUSED) { + IConsolePrint(CC_DEFAULT, "Game cannot be unpaused manually; disable pause_on_join/min_active_clients."); + } else { + IConsolePrint(CC_DEFAULT, "Game is already unpaused."); + } + + return true; +} + +DEF_CONSOLE_CMD(ConRcon) +{ + if (argc == 0) { + IConsoleHelp("Remote control the server from another client. Usage: 'rcon '"); + IConsoleHelp("Remember to enclose the command in quotes, otherwise only the first parameter is sent"); + return true; + } + + if (argc < 3) return false; + + if (_network_server) { + IConsoleCmdExec(argv[2]); + } else { + NetworkClientSendRcon(argv[1], argv[2]); + } + return true; +} + +DEF_CONSOLE_CMD(ConStatus) +{ + if (argc == 0) { + IConsoleHelp("List the status of all clients connected to the server. Usage 'status'"); + return true; + } + + NetworkServerShowStatusToConsole(); + return true; +} + +DEF_CONSOLE_CMD(ConServerInfo) +{ + if (argc == 0) { + IConsoleHelp("List current and maximum client/company limits. Usage 'server_info'"); + IConsoleHelp("You can change these values by modifying settings 'network.max_clients', 'network.max_companies' and 'network.max_spectators'"); + return true; + } + + IConsolePrintF(CC_DEFAULT, "Current/maximum clients: %2d/%2d", _network_game_info.clients_on, _settings_client.network.max_clients); + IConsolePrintF(CC_DEFAULT, "Current/maximum companies: %2d/%2d", (int)Company::GetNumItems(), _settings_client.network.max_companies); + IConsolePrintF(CC_DEFAULT, "Current/maximum spectators: %2d/%2d", NetworkSpectatorCount(), _settings_client.network.max_spectators); + + return true; +} + +DEF_CONSOLE_CMD(ConClientNickChange) +{ + if (argc != 3) { + IConsoleHelp("Change the nickname of a connected client. Usage: 'client_name '"); + IConsoleHelp("For client-id's, see the command 'clients'"); + return true; + } + + ClientID client_id = (ClientID)atoi(argv[1]); + + if (client_id == CLIENT_ID_SERVER) { + IConsoleError("Please use the command 'name' to change your own name!"); + return true; + } + + if (NetworkClientInfo::GetByClientID(client_id) == NULL) { + IConsoleError("Invalid client"); + return true; + } + + if (!NetworkServerChangeClientName(client_id, argv[2])) { + IConsoleError("Cannot give a client a duplicate name"); + } + + return true; +} + +DEF_CONSOLE_CMD(ConJoinCompany) +{ + if (argc < 2) { + IConsoleHelp("Request joining another company. Usage: join []"); + IConsoleHelp("For valid company-id see company list, use 255 for spectator"); + return true; + } + + CompanyID company_id = (CompanyID)(atoi(argv[1]) <= MAX_COMPANIES ? atoi(argv[1]) - 1 : atoi(argv[1])); + + /* Check we have a valid company id! */ + if (!Company::IsValidID(company_id) && company_id != COMPANY_SPECTATOR) { + IConsolePrintF(CC_ERROR, "Company does not exist. Company-id must be between 1 and %d.", MAX_COMPANIES); + return true; + } + + if (NetworkClientInfo::GetByClientID(_network_own_client_id)->client_playas == company_id) { + IConsoleError("You are already there!"); + return true; + } + + if (company_id == COMPANY_SPECTATOR && NetworkMaxSpectatorsReached()) { + IConsoleError("Cannot join spectators, maximum number of spectators reached."); + return true; + } + + if (company_id != COMPANY_SPECTATOR && !Company::IsHumanID(company_id)) { + IConsoleError("Cannot join AI company."); + return true; + } + + /* Check if the company requires a password */ + if (NetworkCompanyIsPassworded(company_id) && argc < 3) { + IConsolePrintF(CC_ERROR, "Company %d requires a password to join.", company_id + 1); + return true; + } + + /* non-dedicated server may just do the move! */ + if (_network_server) { + NetworkServerDoMove(CLIENT_ID_SERVER, company_id); + } else { + NetworkClientRequestMove(company_id, NetworkCompanyIsPassworded(company_id) ? argv[2] : ""); + } + + return true; +} + +DEF_CONSOLE_CMD(ConMoveClient) +{ + if (argc < 3) { + IConsoleHelp("Move a client to another company. Usage: move "); + IConsoleHelp("For valid client-id see 'clients', for valid company-id see 'companies', use 255 for moving to spectators"); + return true; + } + + const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID((ClientID)atoi(argv[1])); + CompanyID company_id = (CompanyID)(atoi(argv[2]) <= MAX_COMPANIES ? atoi(argv[2]) - 1 : atoi(argv[2])); + + /* check the client exists */ + if (ci == NULL) { + IConsoleError("Invalid client-id, check the command 'clients' for valid client-id's."); + return true; + } + + if (!Company::IsValidID(company_id) && company_id != COMPANY_SPECTATOR) { + IConsolePrintF(CC_ERROR, "Company does not exist. Company-id must be between 1 and %d.", MAX_COMPANIES); + return true; + } + + if (company_id != COMPANY_SPECTATOR && !Company::IsHumanID(company_id)) { + IConsoleError("You cannot move clients to AI companies."); + return true; + } + + if (ci->client_id == CLIENT_ID_SERVER && _network_dedicated) { + IConsoleError("Silly boy, you cannot move the server!"); + return true; + } + + if (ci->client_playas == company_id) { + IConsoleError("You cannot move someone to where he/she already is!"); + return true; + } + + /* we are the server, so force the update */ + NetworkServerDoMove(ci->client_id, company_id); + + return true; +} + +DEF_CONSOLE_CMD(ConResetCompany) +{ + if (argc == 0) { + IConsoleHelp("Remove an idle company from the game. Usage: 'reset_company '"); + IConsoleHelp("For company-id's, see the list of companies from the dropdown menu. Company 1 is 1, etc."); + return true; + } + + if (argc != 2) return false; + + CompanyID index = (CompanyID)(atoi(argv[1]) - 1); + + /* Check valid range */ + if (!Company::IsValidID(index)) { + IConsolePrintF(CC_ERROR, "Company does not exist. Company-id must be between 1 and %d.", MAX_COMPANIES); + return true; + } + + if (!Company::IsHumanID(index)) { + IConsoleError("Company is owned by an AI."); + return true; + } + + if (NetworkCompanyHasClients(index)) { + IConsoleError("Cannot remove company: a client is connected to that company."); + return false; + } + const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER); + if (ci->client_playas == index) { + IConsoleError("Cannot remove company: the server is connected to that company."); + return true; + } + + /* It is safe to remove this company */ + DoCommandP(0, 2 | index << 16, CRR_MANUAL, CMD_COMPANY_CTRL); + IConsolePrint(CC_DEFAULT, "Company deleted."); + + return true; +} + +DEF_CONSOLE_CMD(ConNetworkClients) +{ + if (argc == 0) { + IConsoleHelp("Get a list of connected clients including their ID, name, company-id, and IP. Usage: 'clients'"); + return true; + } + + NetworkPrintClients(); + + return true; +} + +DEF_CONSOLE_CMD(ConNetworkReconnect) +{ + if (argc == 0) { + IConsoleHelp("Reconnect to server to which you were connected last time. Usage: 'reconnect []'"); + IConsoleHelp("Company 255 is spectator (default, if not specified), 0 means creating new company."); + IConsoleHelp("All others are a certain company with Company 1 being #1"); + return true; + } + + CompanyID playas = (argc >= 2) ? (CompanyID)atoi(argv[1]) : COMPANY_SPECTATOR; + switch (playas) { + case 0: playas = COMPANY_NEW_COMPANY; break; + case COMPANY_SPECTATOR: /* nothing to do */ break; + default: + /* From a user pov 0 is a new company, internally it's different and all + * companies are offset by one to ease up on users (eg companies 1-8 not 0-7) */ + playas--; + if (playas < COMPANY_FIRST || playas >= MAX_COMPANIES) return false; + break; + } + + if (StrEmpty(_settings_client.network.last_host)) { + IConsolePrint(CC_DEFAULT, "No server for reconnecting."); + return true; + } + + /* Don't resolve the address first, just print it directly as it comes from the config file. */ + IConsolePrintF(CC_DEFAULT, "Reconnecting to %s:%d...", _settings_client.network.last_host, _settings_client.network.last_port); + + NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), playas); + return true; +} + +DEF_CONSOLE_CMD(ConNetworkConnect) +{ + if (argc == 0) { + IConsoleHelp("Connect to a remote OTTD server and join the game. Usage: 'connect '"); + IConsoleHelp("IP can contain port and company: 'IP[:Port][#Company]', eg: 'server.ottd.org:443#2'"); + IConsoleHelp("Company #255 is spectator all others are a certain company with Company 1 being #1"); + return true; + } + + if (argc < 2) return false; + if (_networking) NetworkDisconnect(); // we are in network-mode, first close it! + + const char *port = NULL; + const char *company = NULL; + char *ip = argv[1]; + /* Default settings: default port and new company */ + uint16 rport = NETWORK_DEFAULT_PORT; + CompanyID join_as = COMPANY_NEW_COMPANY; + + ParseConnectionString(&company, &port, ip); + + IConsolePrintF(CC_DEFAULT, "Connecting to %s...", ip); + if (company != NULL) { + join_as = (CompanyID)atoi(company); + IConsolePrintF(CC_DEFAULT, " company-no: %d", join_as); + + /* From a user pov 0 is a new company, internally it's different and all + * companies are offset by one to ease up on users (eg companies 1-8 not 0-7) */ + if (join_as != COMPANY_SPECTATOR) { + if (join_as > MAX_COMPANIES) return false; + join_as--; + } + } + if (port != NULL) { + rport = atoi(port); + IConsolePrintF(CC_DEFAULT, " port: %s", port); + } + + NetworkClientConnectGame(NetworkAddress(ip, rport), join_as); + + return true; +} + +#endif /* ENABLE_NETWORK */ + +/********************************* + * script file console commands + *********************************/ + +DEF_CONSOLE_CMD(ConExec) +{ + if (argc == 0) { + IConsoleHelp("Execute a local script file. Usage: 'exec