From b84a475e14a518efd93a035924b8d29888eb6c24 Mon Sep 17 00:00:00 2001 From: dP Date: Thu, 31 Oct 2019 21:58:04 +0300 Subject: [PATCH] Initialize with OpenTTD 1.9.3 --- CONTRIBUTING.md | 181 + COPYING | 343 + Doxyfile | 355 + Makefile.bundle.in | 229 + Makefile.grf.in | 118 + Makefile.in | 187 + Makefile.lang.in | 89 + Makefile.msvc | 47 + Makefile.setting.in | 65 + Makefile.src.in | 300 + README.md | 839 ++ azure-pipelines-ci.yml | 73 + azure-pipelines-release-stable.yml | 10 + azure-pipelines-release.yml | 7 + azure-pipelines/changelog.sh | 16 + azure-pipelines/manifest.sh | 60 + azure-pipelines/templates/ci-git-rebase.yml | 10 + azure-pipelines/templates/ci-opengfx.yml | 8 + azure-pipelines/templates/linux-build.yml | 36 + .../templates/linux-claim-bundles.yml | 5 + azure-pipelines/templates/osx-build.yml | 5 + .../templates/osx-dependencies.yml | 12 + azure-pipelines/templates/release-bundles.yml | 19 + .../templates/release-fetch-source.yml | 20 + .../templates/release-manifest.yml | 20 + .../templates/release-prepare-source.yml | 35 + azure-pipelines/templates/release.yml | 183 + azure-pipelines/templates/windows-build.yml | 11 + .../templates/windows-dependencies.yml | 14 + .../templates/windows-dependency-nsis.yml | 26 + .../templates/windows-dependency-zip.yml | 5 + bin/ai/compat_0.7.nut | 383 + bin/ai/compat_1.0.nut | 135 + bin/ai/compat_1.1.nut | 72 + bin/ai/compat_1.2.nut | 24 + bin/ai/compat_1.3.nut | 24 + bin/ai/compat_1.4.nut | 24 + bin/ai/compat_1.5.nut | 24 + bin/ai/compat_1.6.nut | 24 + bin/ai/compat_1.7.nut | 24 + bin/ai/compat_1.8.nut | 24 + bin/ai/compat_1.9.nut | 8 + bin/ai/regression/completeness.sh | 69 + bin/ai/regression/empty.sav | Bin 0 -> 97731 bytes bin/ai/regression/regression.cfg | 20 + bin/ai/regression/regression_info.nut | 15 + bin/ai/regression/run.sh | 71 + bin/ai/regression/run.vbs | 154 + bin/ai/regression/tst_regression/main.nut | 1921 ++++ bin/ai/regression/tst_regression/require.nut | 4 + bin/ai/regression/tst_regression/result.txt | 9335 ++++++++++++++++ bin/ai/regression/tst_stationlist/main.nut | 216 + bin/ai/regression/tst_stationlist/result.txt | 127 + bin/ai/regression/tst_stationlist/test.sav | Bin 0 -> 94348 bytes bin/baseset/openttd.grf | Bin 0 -> 502521 bytes bin/baseset/opntitle.dat | Bin 0 -> 54172 bytes bin/baseset/orig_extra.grf | Bin 0 -> 328676 bytes bin/game/compat_1.2.nut | 32 + bin/game/compat_1.3.nut | 32 + bin/game/compat_1.4.nut | 24 + bin/game/compat_1.5.nut | 17 + bin/game/compat_1.6.nut | 17 + bin/game/compat_1.7.nut | 17 + bin/game/compat_1.8.nut | 17 + bin/game/compat_1.9.nut | 8 + bin/scripts/autoexec.scr.example | 4 + bin/scripts/game_start.scr.example | 2 + bin/scripts/on_client.scr.example | 2 + bin/scripts/on_dedicated.scr.example | 4 + bin/scripts/on_server.scr.example | 3 + bin/scripts/on_server_connect.scr.example | 2 + bin/scripts/pre_dedicated.scr.example | 3 + bin/scripts/pre_server.scr.example | 2 + bin/scripts/readme.txt | 23 + changelog.txt | 5810 ++++++++++ config.lib | 3619 +++++++ configure | 173 + docs/HOWTO_compile_lang_files.txt | 72 + docs/Readme_OS2.txt | 139 + docs/Readme_Windows_MSVC.md | 71 + docs/admin_network.txt | 219 + docs/desync.txt | 268 + docs/elrail.svg | 1091 ++ docs/elrail_tile.png | Bin 0 -> 47024 bytes docs/elrail_track.png | Bin 0 -> 47122 bytes docs/landscape.html | 1620 +++ docs/landscape_externals.html | 616 ++ docs/landscape_grid.html | 397 + docs/linkgraph.txt | 30 + docs/multiplayer.txt | 219 + docs/obg_format.txt | 85 + docs/obm_format.txt | 124 + docs/obs_format.txt | 64 + docs/openttd.6 | 153 + docs/ottd-colourtext-palette.png | Bin 0 -> 2126 bytes docs/palettes/openttd.gpl | 260 + docs/palettes/palette.act | Bin 0 -> 768 bytes docs/tileh.png | Bin 0 -> 24558 bytes findversion.sh | 114 + known-bugs.txt | 411 + media/baseset/no_music.obm | 50 + media/baseset/no_sound.obs | 18 + media/baseset/orig_dos.obg | 31 + media/baseset/orig_dos.obm | 76 + media/baseset/orig_dos.obs | 19 + media/baseset/orig_dos_de.obg | 31 + media/baseset/orig_tto.obm | 71 + media/baseset/orig_win.obg | 31 + media/baseset/orig_win.obm | 106 + media/baseset/orig_win.obs | 19 + media/baseset/translations.awk | 69 + media/baseset/translations.vbs | 123 + media/extra_grf/2ccmap.nfo | 2316 ++++ media/extra_grf/airport_preview.nfo | 19 + media/extra_grf/airport_preview.png | Bin 0 -> 29520 bytes media/extra_grf/airports.nfo | 38 + media/extra_grf/airports.png | Bin 0 -> 9491 bytes media/extra_grf/airports_orig_extra.nfo | 12 + media/extra_grf/aqueduct.nfo | 31 + media/extra_grf/aqueduct.png | Bin 0 -> 3609 bytes media/extra_grf/assemble_nfo.awk | 32 + media/extra_grf/autorail.nfo | 65 + media/extra_grf/autorail.png | Bin 0 -> 5503 bytes media/extra_grf/canal_locks.png | Bin 0 -> 16361 bytes media/extra_grf/canals.nfo | 79 + media/extra_grf/canals.png | Bin 0 -> 6236 bytes media/extra_grf/canals_extra.nfo | 101 + media/extra_grf/chars.nfo | 845 ++ media/extra_grf/chars.png | Bin 0 -> 16993 bytes media/extra_grf/chars_orig_extra.nfo | 249 + media/extra_grf/elrails.nfo | 58 + media/extra_grf/elrails.png | Bin 0 -> 6033 bytes media/extra_grf/fix_graphics.nfo | 376 + media/extra_grf/fix_graphics.png | Bin 0 -> 78210 bytes media/extra_grf/flags.nfo | 46 + media/extra_grf/flags.png | Bin 0 -> 1763 bytes media/extra_grf/foundations.nfo | 377 + media/extra_grf/foundations.png | Bin 0 -> 54976 bytes media/extra_grf/mono.nfo | 240 + media/extra_grf/mono.png | Bin 0 -> 4856 bytes media/extra_grf/oneway.nfo | 16 + media/extra_grf/oneway.png | Bin 0 -> 1222 bytes media/extra_grf/openttd.nfo | 103 + media/extra_grf/openttdgui.nfo | 189 + media/extra_grf/openttdgui.png | Bin 0 -> 26393 bytes media/extra_grf/openttdgui_group_livery.png | Bin 0 -> 1426 bytes media/extra_grf/orig_extra.nfo | 87 + media/extra_grf/palette.nfo | 20 + media/extra_grf/rivers/arctic.nfo | 282 + media/extra_grf/rivers/arctic_brown.png | Bin 0 -> 15024 bytes media/extra_grf/rivers/arctic_snowy.png | Bin 0 -> 13796 bytes media/extra_grf/rivers/rapids.nfo | 139 + media/extra_grf/rivers/rapids.png | Bin 0 -> 17651 bytes media/extra_grf/rivers/temperate.nfo | 146 + media/extra_grf/rivers/temperate.png | Bin 0 -> 16127 bytes media/extra_grf/rivers/toyland.nfo | 146 + media/extra_grf/rivers/toyland.png | Bin 0 -> 16127 bytes media/extra_grf/rivers/tropic.nfo | 282 + media/extra_grf/rivers/tropic_desert.png | Bin 0 -> 15582 bytes media/extra_grf/rivers/tropic_forest.png | Bin 0 -> 15157 bytes media/extra_grf/roadstops.nfo | 18 + media/extra_grf/roadstops.png | Bin 0 -> 2621 bytes media/extra_grf/shore.nfo | 61 + media/extra_grf/shore.png | Bin 0 -> 21568 bytes media/extra_grf/signals.nfo | 493 + media/extra_grf/signals.png | Bin 0 -> 23747 bytes media/extra_grf/sloped_tracks.nfo | 22 + media/extra_grf/sloped_tracks.png | Bin 0 -> 2495 bytes media/extra_grf/tramtracks.nfo | 123 + media/extra_grf/tramtracks.png | Bin 0 -> 25946 bytes media/extra_grf/tunnel_portals.nfo | 74 + media/extra_grf/tunnel_portals.png | Bin 0 -> 18680 bytes media/openttd.128.png | Bin 0 -> 19290 bytes media/openttd.16.png | Bin 0 -> 894 bytes media/openttd.256.png | Bin 0 -> 16161 bytes media/openttd.32.bmp | Bin 0 -> 2104 bytes media/openttd.32.png | Bin 0 -> 2475 bytes media/openttd.32.xpm | 295 + media/openttd.48.png | Bin 0 -> 4551 bytes media/openttd.64.png | Bin 0 -> 6803 bytes media/openttd.64.xpm | 319 + media/openttd.desktop.filter.awk | 13 + media/openttd.desktop.in | 12 + media/openttd.desktop.translation.awk | 15 + media/openttd.ico | Bin 0 -> 39814 bytes media/openttd.svg | 265 + os/debian/NEWS | 25 + os/debian/README.Debian | 41 + os/debian/changelog | 1076 ++ os/debian/compat | 1 + os/debian/control | 36 + os/debian/copyright | 106 + os/debian/gbp.conf | 13 + os/debian/menu | 2 + os/debian/openttd-wrapper | 28 + os/debian/patches/run-openttd-wrapper.patch | 20 + os/debian/patches/series | 1 + os/debian/rules | 50 + os/debian/source/format | 1 + os/debian/watch | 5 + os/dos/cwsdpmi/README.licensing | 3 + os/dos/cwsdpmi/cwsdpmi.exe | Bin 0 -> 20125 bytes os/dos/cwsdpmi/cwsdpmi.txt | 173 + os/dos/cwsdpmi/cwsdstub.exe | Bin 0 -> 21504 bytes os/dos/exe2coff/README.licensing | 3 + os/dos/exe2coff/copying | 339 + os/dos/exe2coff/copying.dj | 48 + os/dos/exe2coff/copying.lib | 481 + os/dos/exe2coff/exe2coff.c | 94 + os/dos/make_dos_binary_selfcontained.sh | 11 + os/macosx/openttd.icns | Bin 0 -> 213612 bytes os/macosx/plistgen.sh | 48 + os/macosx/splash.png | Bin 0 -> 20053 bytes os/morphos/icons/OpenTTD.info | Bin 0 -> 7341 bytes os/morphos/icons/docs.info | Bin 0 -> 5390 bytes os/morphos/icons/document.info | Bin 0 -> 4451 bytes os/morphos/icons/drawer.info | Bin 0 -> 5390 bytes os/os2/build_lang.cmd | 8 + os/os2/dedicated.cmd | 1 + os/os2/installer/download_nosound.cmd | 21 + os/os2/installer/download_opengfx.cmd | 21 + os/os2/installer/download_opensfx.cmd | 21 + os/os2/installer/make_installer.cmd | 85 + os/os2/installer/openttd.wis | 106 + os/os2/installer/remove_nosound.cmd | 15 + os/os2/installer/remove_opengfx.cmd | 15 + os/os2/installer/remove_opensfx.cmd | 15 + os/os2/openttd.wpj | 64 + os/os2/svn_version.cmd | 30 + os/os2/svnver1.c | 3 + os/os2/svnver2.c | 4 + os/rpm/openttd-rpmlintrc | 6 + os/rpm/openttd.changes | 100 + os/rpm/openttd.spec | 272 + os/windows/installer/build_installers.bat | 4 + os/windows/installer/cdfinder.ini | 26 + os/windows/installer/install.nsi | 744 ++ os/windows/installer/top.bmp | Bin 0 -> 25820 bytes os/windows/installer/version_win32.txt | 5 + os/windows/installer/version_win64.txt | 5 + os/windows/installer/version_win9x.txt | 5 + os/windows/installer/welcome.bmp | Bin 0 -> 154544 bytes projects/basesets_vs140.vcxproj | 99 + projects/basesets_vs140.vcxproj.filters | 40 + projects/basesets_vs140.vcxproj.filters.in | 11 + projects/basesets_vs140.vcxproj.in | 40 + projects/basesets_vs141.vcxproj | 99 + projects/basesets_vs141.vcxproj.filters | 40 + projects/basesets_vs141.vcxproj.filters.in | 11 + projects/basesets_vs141.vcxproj.in | 40 + projects/basesets_vs142.vcxproj | 99 + projects/basesets_vs142.vcxproj.filters | 40 + projects/basesets_vs142.vcxproj.filters.in | 11 + projects/basesets_vs142.vcxproj.in | 40 + projects/determineversion.vbs | 212 + projects/dpi_aware.manifest | 29 + projects/gen-kdev4.sh | 203 + projects/generate | 334 + projects/generate.vbs | 409 + projects/generate_vs140.vcxproj | 39 + projects/generate_vs141.vcxproj | 39 + projects/generate_vs142.vcxproj | 40 + projects/langs_vs140.vcxproj | 390 + projects/langs_vs140.vcxproj.filters | 176 + projects/langs_vs140.vcxproj.filters.in | 12 + projects/langs_vs140.vcxproj.in | 61 + projects/langs_vs141.vcxproj | 390 + projects/langs_vs141.vcxproj.filters | 176 + projects/langs_vs141.vcxproj.filters.in | 12 + projects/langs_vs141.vcxproj.in | 61 + projects/langs_vs142.vcxproj | 390 + projects/langs_vs142.vcxproj.filters | 176 + projects/langs_vs142.vcxproj.filters.in | 12 + projects/langs_vs142.vcxproj.in | 61 + projects/openttd_vs140.sln | 103 + projects/openttd_vs140.vcxproj | 1368 +++ projects/openttd_vs140.vcxproj.filters | 3095 ++++++ projects/openttd_vs140.vcxproj.filters.in | 13 + projects/openttd_vs140.vcxproj.in | 374 + projects/openttd_vs141.sln | 103 + projects/openttd_vs141.vcxproj | 1368 +++ projects/openttd_vs141.vcxproj.filters | 3095 ++++++ projects/openttd_vs141.vcxproj.filters.in | 13 + projects/openttd_vs141.vcxproj.in | 374 + projects/openttd_vs142.sln | 105 + projects/openttd_vs142.vcxproj | 1368 +++ projects/openttd_vs142.vcxproj.filters | 3095 ++++++ projects/openttd_vs142.vcxproj.filters.in | 13 + projects/openttd_vs142.vcxproj.in | 374 + projects/os_versions.manifest | 17 + projects/regression.bat | 6 + projects/regression_vs140.vcxproj | 41 + projects/regression_vs141.vcxproj | 41 + projects/regression_vs142.vcxproj | 41 + projects/settings_vs140.vcxproj | 60 + projects/settings_vs140.vcxproj.filters | 35 + projects/settings_vs140.vcxproj.filters.in | 15 + projects/settings_vs140.vcxproj.in | 54 + projects/settings_vs141.vcxproj | 60 + projects/settings_vs141.vcxproj.filters | 35 + projects/settings_vs141.vcxproj.filters.in | 15 + projects/settings_vs141.vcxproj.in | 54 + projects/settings_vs142.vcxproj | 60 + projects/settings_vs142.vcxproj.filters | 35 + projects/settings_vs142.vcxproj.filters.in | 15 + projects/settings_vs142.vcxproj.in | 54 + projects/settingsgen_vs140.vcxproj | 83 + projects/settingsgen_vs140.vcxproj.filters | 32 + projects/settingsgen_vs141.vcxproj | 83 + projects/settingsgen_vs141.vcxproj.filters | 32 + projects/settingsgen_vs142.vcxproj | 84 + projects/settingsgen_vs142.vcxproj.filters | 32 + projects/strgen_vs140.vcxproj | 95 + projects/strgen_vs140.vcxproj.filters | 35 + projects/strgen_vs141.vcxproj | 95 + projects/strgen_vs141.vcxproj.filters | 35 + projects/strgen_vs142.vcxproj | 96 + projects/strgen_vs142.vcxproj.filters | 35 + projects/version_vs140.vcxproj | 42 + projects/version_vs141.vcxproj | 42 + projects/version_vs142.vcxproj | 42 + source.list | 1198 +++ src/3rdparty/README.licensing | 3 + src/3rdparty/md5/md5.cpp | 325 + src/3rdparty/md5/md5.h | 72 + src/3rdparty/os2/getaddrinfo.c | 299 + src/3rdparty/os2/getaddrinfo.h | 101 + src/3rdparty/os2/getnameinfo.c | 367 + src/3rdparty/os2/getnameinfo.h | 29 + src/3rdparty/squirrel/COPYRIGHT | 29 + src/3rdparty/squirrel/README.OpenTTD | 4 + src/3rdparty/squirrel/include/sqstdaux.h | 8 + src/3rdparty/squirrel/include/sqstdmath.h | 7 + src/3rdparty/squirrel/include/sqstdstring.h | 25 + src/3rdparty/squirrel/include/squirrel.h | 371 + src/3rdparty/squirrel/sqstdlib/sqstdaux.cpp | 146 + src/3rdparty/squirrel/sqstdlib/sqstdmath.cpp | 118 + src/3rdparty/squirrel/sqstdlib/sqstdrex.cpp | 632 ++ .../squirrel/sqstdlib/sqstdstring.cpp | 366 + src/3rdparty/squirrel/squirrel/sqapi.cpp | 1326 +++ src/3rdparty/squirrel/squirrel/sqarray.h | 87 + src/3rdparty/squirrel/squirrel/sqbaselib.cpp | 962 ++ src/3rdparty/squirrel/squirrel/sqclass.cpp | 199 + src/3rdparty/squirrel/squirrel/sqclass.h | 162 + src/3rdparty/squirrel/squirrel/sqclosure.h | 122 + src/3rdparty/squirrel/squirrel/sqcompiler.cpp | 1372 +++ src/3rdparty/squirrel/squirrel/sqcompiler.h | 82 + src/3rdparty/squirrel/squirrel/sqdebug.cpp | 126 + src/3rdparty/squirrel/squirrel/sqfuncproto.h | 166 + .../squirrel/squirrel/sqfuncstate.cpp | 569 + src/3rdparty/squirrel/squirrel/sqfuncstate.h | 85 + src/3rdparty/squirrel/squirrel/sqlexer.cpp | 491 + src/3rdparty/squirrel/squirrel/sqlexer.h | 42 + src/3rdparty/squirrel/squirrel/sqmem.cpp | 16 + src/3rdparty/squirrel/squirrel/sqobject.cpp | 592 + src/3rdparty/squirrel/squirrel/sqobject.h | 381 + src/3rdparty/squirrel/squirrel/sqopcodes.h | 115 + src/3rdparty/squirrel/squirrel/sqpcheader.h | 15 + src/3rdparty/squirrel/squirrel/sqstate.cpp | 585 + src/3rdparty/squirrel/squirrel/sqstate.h | 133 + src/3rdparty/squirrel/squirrel/sqstring.h | 31 + src/3rdparty/squirrel/squirrel/sqtable.cpp | 201 + src/3rdparty/squirrel/squirrel/sqtable.h | 91 + src/3rdparty/squirrel/squirrel/squserdata.h | 37 + src/3rdparty/squirrel/squirrel/squtils.h | 112 + src/3rdparty/squirrel/squirrel/sqvm.cpp | 1607 +++ src/3rdparty/squirrel/squirrel/sqvm.h | 225 + src/ai/ai.hpp | 178 + src/ai/ai_config.cpp | 129 + src/ai/ai_config.hpp | 52 + src/ai/ai_core.cpp | 394 + src/ai/ai_gui.cpp | 1571 +++ src/ai/ai_gui.hpp | 22 + src/ai/ai_info.cpp | 184 + src/ai/ai_info.hpp | 84 + src/ai/ai_instance.cpp | 272 + src/ai/ai_instance.hpp | 38 + src/ai/ai_scanner.cpp | 171 + src/ai/ai_scanner.hpp | 75 + src/aircraft.h | 150 + src/aircraft_cmd.cpp | 2122 ++++ src/aircraft_gui.cpp | 115 + src/airport.cpp | 235 + src/airport.h | 202 + src/airport_gui.cpp | 605 ++ src/animated_tile.cpp | 79 + src/animated_tile_func.h | 22 + src/articulated_vehicles.cpp | 451 + src/articulated_vehicles.h | 30 + src/autoreplace.cpp | 146 + src/autoreplace_base.h | 49 + src/autoreplace_cmd.cpp | 789 ++ src/autoreplace_func.h | 102 + src/autoreplace_gui.cpp | 709 ++ src/autoreplace_gui.h | 23 + src/autoreplace_type.h | 22 + src/autoslope.h | 53 + src/base_consist.cpp | 51 + src/base_consist.h | 40 + src/base_media_base.h | 326 + src/base_media_func.h | 411 + src/base_station_base.h | 255 + src/blitter/32bpp_anim.cpp | 543 + src/blitter/32bpp_anim.hpp | 83 + src/blitter/32bpp_anim_sse2.cpp | 100 + src/blitter/32bpp_anim_sse2.hpp | 43 + src/blitter/32bpp_anim_sse4.cpp | 415 + src/blitter/32bpp_anim_sse4.hpp | 54 + src/blitter/32bpp_base.cpp | 188 + src/blitter/32bpp_base.hpp | 161 + src/blitter/32bpp_optimized.cpp | 401 + src/blitter/32bpp_optimized.hpp | 41 + src/blitter/32bpp_simple.cpp | 155 + src/blitter/32bpp_simple.hpp | 43 + src/blitter/32bpp_sse2.cpp | 143 + src/blitter/32bpp_sse2.hpp | 104 + src/blitter/32bpp_sse4.cpp | 25 + src/blitter/32bpp_sse4.hpp | 44 + src/blitter/32bpp_sse_func.hpp | 467 + src/blitter/32bpp_sse_type.h | 58 + src/blitter/32bpp_ssse3.cpp | 25 + src/blitter/32bpp_ssse3.hpp | 44 + src/blitter/8bpp_base.cpp | 162 + src/blitter/8bpp_base.hpp | 36 + src/blitter/8bpp_optimized.cpp | 232 + src/blitter/8bpp_optimized.hpp | 40 + src/blitter/8bpp_simple.cpp | 81 + src/blitter/8bpp_simple.hpp | 34 + src/blitter/base.hpp | 210 + src/blitter/common.hpp | 197 + src/blitter/factory.hpp | 196 + src/blitter/null.cpp | 31 + src/blitter/null.hpp | 47 + src/bmp.cpp | 419 + src/bmp.h | 47 + src/bootstrap_gui.cpp | 269 + src/bridge.h | 80 + src/bridge_gui.cpp | 436 + src/bridge_map.cpp | 80 + src/bridge_map.h | 184 + src/build_vehicle_gui.cpp | 1520 +++ src/cargo_type.h | 158 + src/cargoaction.cpp | 240 + src/cargoaction.h | 146 + src/cargomonitor.cpp | 161 + src/cargomonitor.h | 154 + src/cargopacket.cpp | 874 ++ src/cargopacket.h | 571 + src/cargotype.cpp | 195 + src/cargotype.h | 175 + src/cheat.cpp | 41 + src/cheat_func.h | 23 + src/cheat_gui.cpp | 422 + src/cheat_type.h | 44 + src/clear_cmd.cpp | 403 + src/clear_func.h | 20 + src/clear_map.h | 325 + src/cmd_helper.h | 36 + src/command.cpp | 808 ++ src/command_func.h | 128 + src/command_type.h | 484 + src/company_base.h | 178 + src/company_cmd.cpp | 1172 ++ src/company_func.h | 62 + src/company_gui.cpp | 2822 +++++ src/company_gui.h | 31 + src/company_manager_face.h | 245 + src/company_type.h | 76 + src/console.cpp | 520 + src/console_cmds.cpp | 2064 ++++ src/console_func.h | 37 + src/console_gui.cpp | 528 + src/console_gui.h | 20 + src/console_internal.h | 88 + src/console_type.h | 33 + src/core/alloc_func.cpp | 32 + src/core/alloc_func.hpp | 138 + src/core/alloc_type.hpp | 217 + src/core/backup_type.hpp | 149 + src/core/bitmath_func.cpp | 81 + src/core/bitmath_func.hpp | 403 + src/core/endian_func.hpp | 57 + src/core/endian_type.hpp | 47 + src/core/enum_type.hpp | 179 + src/core/geometry_func.cpp | 30 + src/core/geometry_func.hpp | 19 + src/core/geometry_type.hpp | 64 + src/core/math_func.cpp | 101 + src/core/math_func.hpp | 368 + src/core/mem_func.hpp | 103 + src/core/multimap.hpp | 388 + src/core/overflowsafe_type.hpp | 157 + src/core/pool_func.cpp | 40 + src/core/pool_func.hpp | 232 + src/core/pool_type.hpp | 322 + src/core/random_func.cpp | 87 + src/core/random_func.hpp | 164 + src/core/smallmap_type.hpp | 158 + src/core/smallmatrix_type.hpp | 322 + src/core/smallstack_type.hpp | 290 + src/core/smallvec_type.hpp | 451 + src/core/sort_func.hpp | 89 + src/core/string_compare_type.hpp | 29 + src/cpu.cpp | 139 + src/cpu.h | 37 + src/crashlog.cpp | 511 + src/crashlog.h | 123 + src/currency.cpp | 179 + src/currency.h | 98 + src/date.cpp | 310 + src/date_func.h | 37 + src/date_gui.cpp | 219 + src/date_gui.h | 27 + src/date_type.h | 113 + src/debug.cpp | 268 + src/debug.h | 109 + src/dedicated.cpp | 77 + src/depend/depend.cpp | 1066 ++ src/depot.cpp | 51 + src/depot_base.h | 52 + src/depot_cmd.cpp | 85 + src/depot_func.h | 37 + src/depot_gui.cpp | 1133 ++ src/depot_map.h | 78 + src/depot_type.h | 20 + src/direction_func.h | 281 + src/direction_type.h | 136 + src/disaster_vehicle.cpp | 983 ++ src/disaster_vehicle.h | 62 + src/dock_gui.cpp | 587 + src/driver.cpp | 252 + src/driver.h | 142 + src/economy.cpp | 2140 ++++ src/economy_base.h | 65 + src/economy_func.h | 54 + src/economy_type.h | 223 + src/effectvehicle.cpp | 666 ++ src/effectvehicle_base.h | 46 + src/effectvehicle_func.h | 38 + src/elrail.cpp | 644 ++ src/elrail_func.h | 43 + src/engine.cpp | 1157 ++ src/engine_base.h | 200 + src/engine_func.h | 35 + src/engine_gui.cpp | 349 + src/engine_gui.h | 45 + src/engine_type.h | 176 + src/error.h | 64 + src/error_gui.cpp | 443 + src/fileio.cpp | 1470 +++ src/fileio_func.h | 166 + src/fileio_type.h | 150 + src/fios.cpp | 793 ++ src/fios.h | 231 + src/fios_gui.cpp | 911 ++ src/fontcache.cpp | 690 ++ src/fontcache.h | 229 + src/fontdetection.cpp | 732 ++ src/fontdetection.h | 44 + src/framerate_gui.cpp | 1027 ++ src/framerate_type.h | 127 + src/game/game.hpp | 133 + src/game/game_config.cpp | 46 + src/game/game_config.hpp | 48 + src/game/game_core.cpp | 287 + src/game/game_info.cpp | 144 + src/game/game_info.hpp | 76 + src/game/game_instance.cpp | 270 + src/game/game_instance.hpp | 38 + src/game/game_scanner.cpp | 112 + src/game/game_scanner.hpp | 59 + src/game/game_text.cpp | 402 + src/game/game_text.hpp | 42 + src/gamelog.cpp | 822 ++ src/gamelog.h | 67 + src/gamelog_internal.h | 92 + src/genworld.cpp | 356 + src/genworld.h | 106 + src/genworld_gui.cpp | 1358 +++ src/gfx.cpp | 1714 +++ src/gfx_func.h | 229 + src/gfx_layout.cpp | 901 ++ src/gfx_layout.h | 204 + src/gfx_type.h | 322 + src/gfxinit.cpp | 464 + src/gfxinit.h | 17 + src/goal.cpp | 320 + src/goal_base.h | 45 + src/goal_gui.cpp | 492 + src/goal_type.h | 39 + src/graph_gui.cpp | 1585 +++ src/graph_gui.h | 24 + src/ground_vehicle.cpp | 211 + src/ground_vehicle.hpp | 392 + src/group.h | 112 + src/group_cmd.cpp | 837 ++ src/group_gui.cpp | 1033 ++ src/group_gui.h | 21 + src/group_type.h | 26 + src/gui.h | 70 + src/guitimer_func.h | 65 + src/heightmap.cpp | 523 + src/heightmap.h | 31 + src/highscore.cpp | 183 + src/highscore.h | 39 + src/highscore_gui.cpp | 250 + src/hotkeys.cpp | 351 + src/hotkeys.h | 73 + src/house.h | 148 + src/house_type.h | 20 + src/industry.h | 202 + src/industry_cmd.cpp | 2911 +++++ src/industry_gui.cpp | 2837 +++++ src/industry_map.h | 293 + src/industry_type.h | 46 + src/industrytype.h | 207 + src/ini.cpp | 130 + src/ini_load.cpp | 325 + src/ini_type.h | 97 + src/intro_gui.cpp | 338 + src/landscape.cpp | 1402 +++ src/landscape.h | 146 + src/landscape_type.h | 38 + src/lang/afrikaans.txt | 4952 +++++++++ src/lang/arabic_egypt.txt | 4412 ++++++++ src/lang/basque.txt | 4818 +++++++++ src/lang/belarusian.txt | 5458 ++++++++++ src/lang/brazilian_portuguese.txt | 5028 +++++++++ src/lang/bulgarian.txt | 4918 +++++++++ src/lang/catalan.txt | 5069 +++++++++ src/lang/croatian.txt | 5202 +++++++++ src/lang/czech.txt | 5235 +++++++++ src/lang/danish.txt | 5069 +++++++++ src/lang/dutch.txt | 5069 +++++++++ src/lang/english.txt | 5069 +++++++++ src/lang/english_AU.txt | 4899 +++++++++ src/lang/english_US.txt | 5069 +++++++++ src/lang/esperanto.txt | 4313 ++++++++ src/lang/estonian.txt | 5034 +++++++++ src/lang/faroese.txt | 4457 ++++++++ src/lang/finnish.txt | 5069 +++++++++ src/lang/french.txt | 5070 +++++++++ src/lang/gaelic.txt | 5405 ++++++++++ src/lang/galician.txt | 4971 +++++++++ src/lang/german.txt | 5054 +++++++++ src/lang/greek.txt | 5186 +++++++++ src/lang/hebrew.txt | 5029 +++++++++ src/lang/hungarian.txt | 5174 +++++++++ src/lang/icelandic.txt | 4708 ++++++++ src/lang/indonesian.txt | 5012 +++++++++ src/lang/irish.txt | 4951 +++++++++ src/lang/italian.txt | 5099 +++++++++ src/lang/japanese.txt | 4954 +++++++++ src/lang/korean.txt | 5070 +++++++++ src/lang/latin.txt | 5346 +++++++++ src/lang/latvian.txt | 4880 +++++++++ src/lang/lithuanian.txt | 5491 ++++++++++ src/lang/luxembourgish.txt | 5048 +++++++++ src/lang/malay.txt | 4622 ++++++++ src/lang/norwegian_bokmal.txt | 5074 +++++++++ src/lang/norwegian_nynorsk.txt | 4867 +++++++++ src/lang/polish.txt | 5455 ++++++++++ src/lang/portuguese.txt | 5070 +++++++++ src/lang/romanian.txt | 4937 +++++++++ src/lang/russian.txt | 5296 +++++++++ src/lang/serbian.txt | 5195 +++++++++ src/lang/simplified_chinese.txt | 4991 +++++++++ src/lang/slovak.txt | 5020 +++++++++ src/lang/slovenian.txt | 5155 +++++++++ src/lang/spanish.txt | 5070 +++++++++ src/lang/spanish_MX.txt | 5070 +++++++++ src/lang/swedish.txt | 5069 +++++++++ src/lang/tamil.txt | 4504 ++++++++ src/lang/thai.txt | 4861 +++++++++ src/lang/traditional_chinese.txt | 4951 +++++++++ src/lang/turkish.txt | 5072 +++++++++ src/lang/ukrainian.txt | 5235 +++++++++ src/lang/unfinished/chuvash.txt | 1534 +++ src/lang/unfinished/frisian.txt | 4504 ++++++++ src/lang/unfinished/ido.txt | 1395 +++ src/lang/unfinished/macedonian.txt | 1963 ++++ src/lang/unfinished/maltese.txt | 1437 +++ src/lang/unfinished/marathi.txt | 1851 ++++ src/lang/unfinished/persian.txt | 4111 +++++++ src/lang/unfinished/urdu.txt | 3005 ++++++ src/lang/vietnamese.txt | 5031 +++++++++ src/lang/welsh.txt | 4982 +++++++++ src/language.h | 114 + src/linkgraph/demands.cpp | 283 + src/linkgraph/demands.h | 43 + src/linkgraph/flowmapper.cpp | 69 + src/linkgraph/flowmapper.h | 47 + src/linkgraph/init.h | 27 + src/linkgraph/linkgraph.cpp | 291 + src/linkgraph/linkgraph.h | 541 + src/linkgraph/linkgraph_base.h | 27 + src/linkgraph/linkgraph_gui.cpp | 659 ++ src/linkgraph/linkgraph_gui.h | 120 + src/linkgraph/linkgraph_type.h | 64 + src/linkgraph/linkgraphjob.cpp | 279 + src/linkgraph/linkgraphjob.h | 436 + src/linkgraph/linkgraphjob_base.h | 23 + src/linkgraph/linkgraphschedule.cpp | 160 + src/linkgraph/linkgraphschedule.h | 81 + src/linkgraph/mcf.cpp | 600 ++ src/linkgraph/mcf.h | 92 + src/linkgraph/refresh.cpp | 324 + src/linkgraph/refresh.h | 103 + src/livery.h | 88 + src/main_gui.cpp | 613 ++ src/map.cpp | 389 + src/map_func.h | 441 + src/map_type.h | 89 + src/misc.cpp | 122 + src/misc/array.hpp | 120 + src/misc/binaryheap.hpp | 305 + src/misc/blob.hpp | 423 + src/misc/countedobj.cpp | 37 + src/misc/countedptr.hpp | 221 + src/misc/dbg_helpers.cpp | 183 + src/misc/dbg_helpers.h | 176 + src/misc/fixedsizearray.hpp | 160 + src/misc/getoptdata.cpp | 85 + src/misc/getoptdata.h | 112 + src/misc/hashtable.hpp | 259 + src/misc/str.hpp | 151 + src/misc_cmd.cpp | 275 + src/misc_gui.cpp | 1221 +++ src/mixer.cpp | 243 + src/mixer.h | 35 + src/music.cpp | 197 + src/music/allegro_m.cpp | 90 + src/music/allegro_m.h | 49 + src/music/bemidi.cpp | 65 + src/music/bemidi.h | 41 + src/music/cocoa_m.cpp | 249 + src/music/cocoa_m.h | 39 + src/music/dmusic.cpp | 1250 +++ src/music/dmusic.h | 43 + src/music/extmidi.cpp | 163 + src/music/extmidi.h | 47 + src/music/fluidsynth.cpp | 159 + src/music/fluidsynth.h | 41 + src/music/libtimidity.cpp | 128 + src/music/libtimidity.h | 41 + src/music/midi.h | 159 + src/music/midifile.cpp | 1158 ++ src/music/midifile.hpp | 55 + src/music/music_driver.hpp | 55 + src/music/null_m.cpp | 18 + src/music/null_m.h | 41 + src/music/os2_m.cpp | 93 + src/music/os2_m.h | 41 + src/music/qtmidi.cpp | 344 + src/music/qtmidi.h | 39 + src/music/win32_m.cpp | 430 + src/music/win32_m.h | 41 + src/music_gui.cpp | 931 ++ src/network/core/address.cpp | 437 + src/network/core/address.h | 196 + src/network/core/config.h | 74 + src/network/core/core.cpp | 131 + src/network/core/core.h | 85 + src/network/core/game.h | 63 + src/network/core/host.cpp | 211 + src/network/core/host.h | 21 + src/network/core/os_abstraction.h | 242 + src/network/core/packet.cpp | 314 + src/network/core/packet.h | 92 + src/network/core/tcp.cpp | 251 + src/network/core/tcp.h | 104 + src/network/core/tcp_admin.cpp | 176 + src/network/core/tcp_admin.h | 505 + src/network/core/tcp_connect.cpp | 101 + src/network/core/tcp_content.cpp | 270 + src/network/core/tcp_content.h | 218 + src/network/core/tcp_game.cpp | 203 + src/network/core/tcp_game.h | 563 + src/network/core/tcp_http.cpp | 339 + src/network/core/tcp_http.h | 127 + src/network/core/tcp_listen.h | 182 + src/network/core/udp.cpp | 353 + src/network/core/udp.h | 251 + src/network/network.cpp | 1176 ++ src/network/network.h | 44 + src/network/network_admin.cpp | 1049 ++ src/network/network_admin.h | 128 + src/network/network_base.h | 58 + src/network/network_chat_gui.cpp | 566 + src/network/network_client.cpp | 1324 +++ src/network/network_client.h | 123 + src/network/network_command.cpp | 348 + src/network/network_content.cpp | 1094 ++ src/network/network_content.h | 160 + src/network/network_content_gui.cpp | 1172 ++ src/network/network_content_gui.h | 48 + src/network/network_func.h | 94 + src/network/network_gamelist.cpp | 210 + src/network/network_gamelist.h | 36 + src/network/network_gui.cpp | 2245 ++++ src/network/network_gui.h | 55 + src/network/network_internal.h | 175 + src/network/network_server.cpp | 2210 ++++ src/network/network_server.h | 149 + src/network/network_type.h | 134 + src/network/network_udp.cpp | 718 ++ src/network/network_udp.h | 30 + src/newgrf.cpp | 9537 +++++++++++++++++ src/newgrf.h | 198 + src/newgrf_airport.cpp | 289 + src/newgrf_airport.h | 149 + src/newgrf_airporttiles.cpp | 306 + src/newgrf_airporttiles.h | 89 + src/newgrf_animation_base.h | 138 + src/newgrf_animation_type.h | 64 + src/newgrf_callbacks.h | 409 + src/newgrf_canal.cpp | 175 + src/newgrf_canal.h | 40 + src/newgrf_cargo.cpp | 94 + src/newgrf_cargo.h | 31 + src/newgrf_class.h | 68 + src/newgrf_class_func.h | 231 + src/newgrf_commons.cpp | 798 ++ src/newgrf_commons.h | 336 + src/newgrf_config.cpp | 927 ++ src/newgrf_config.h | 241 + src/newgrf_debug.h | 47 + src/newgrf_debug_gui.cpp | 1099 ++ src/newgrf_engine.cpp | 1306 +++ src/newgrf_engine.h | 125 + src/newgrf_generic.cpp | 261 + src/newgrf_generic.h | 64 + src/newgrf_gui.cpp | 2300 ++++ src/newgrf_house.cpp | 671 ++ src/newgrf_house.h | 118 + src/newgrf_industries.cpp | 671 ++ src/newgrf_industries.h | 101 + src/newgrf_industrytiles.cpp | 373 + src/newgrf_industrytiles.h | 76 + src/newgrf_object.cpp | 553 + src/newgrf_object.h | 167 + src/newgrf_properties.h | 59 + src/newgrf_railtype.cpp | 151 + src/newgrf_railtype.h | 61 + src/newgrf_sound.cpp | 227 + src/newgrf_sound.h | 42 + src/newgrf_spritegroup.cpp | 316 + src/newgrf_spritegroup.h | 405 + src/newgrf_station.cpp | 1045 ++ src/newgrf_station.h | 201 + src/newgrf_storage.cpp | 101 + src/newgrf_storage.h | 238 + src/newgrf_text.cpp | 1148 ++ src/newgrf_text.h | 69 + src/newgrf_town.cpp | 163 + src/newgrf_town.h | 58 + src/newgrf_townname.cpp | 141 + src/newgrf_townname.h | 55 + src/news_func.h | 67 + src/news_gui.cpp | 1150 ++ src/news_gui.h | 22 + src/news_type.h | 161 + src/object.h | 25 + src/object_base.h | 97 + src/object_cmd.cpp | 851 ++ src/object_gui.cpp | 536 + src/object_map.h | 89 + src/object_type.h | 38 + src/openttd.cpp | 1509 +++ src/openttd.h | 83 + src/order_backup.cpp | 279 + src/order_backup.h | 82 + src/order_base.h | 405 + src/order_cmd.cpp | 2298 ++++ src/order_func.h | 38 + src/order_gui.cpp | 1737 +++ src/order_type.h | 195 + src/os/macosx/G5_detector.cpp | 38 + src/os/macosx/crashlog_osx.cpp | 256 + src/os/macosx/macos.h | 43 + src/os/macosx/macos.mm | 254 + src/os/macosx/osx_stdafx.h | 130 + src/os/macosx/splash.cpp | 187 + src/os/macosx/splash.h | 19 + src/os/macosx/string_osx.cpp | 457 + src/os/macosx/string_osx.h | 90 + src/os/os2/os2.cpp | 228 + src/os/unix/crashlog_unix.cpp | 185 + src/os/unix/unix.cpp | 378 + src/os/windows/crashlog_win.cpp | 697 ++ src/os/windows/ottdres.rc.in | 125 + src/os/windows/string_uniscribe.cpp | 611 ++ src/os/windows/string_uniscribe.h | 92 + src/os/windows/win32.cpp | 835 ++ src/os/windows/win32.h | 51 + src/osk_gui.cpp | 448 + src/pathfinder/follow_track.hpp | 484 + src/pathfinder/npf/aystar.cpp | 306 + src/pathfinder/npf/aystar.h | 173 + src/pathfinder/npf/npf.cpp | 1284 +++ src/pathfinder/npf/npf_func.h | 93 + src/pathfinder/npf/queue.cpp | 494 + src/pathfinder/npf/queue.h | 111 + src/pathfinder/opf/opf_ship.cpp | 222 + src/pathfinder/opf/opf_ship.h | 31 + src/pathfinder/pathfinder_func.h | 51 + src/pathfinder/pathfinder_type.h | 66 + src/pathfinder/pf_performance_timer.hpp | 82 + src/pathfinder/yapf/nodelist.hpp | 162 + src/pathfinder/yapf/yapf.h | 101 + src/pathfinder/yapf/yapf.hpp | 40 + src/pathfinder/yapf/yapf_base.hpp | 381 + src/pathfinder/yapf/yapf_cache.h | 24 + src/pathfinder/yapf/yapf_common.hpp | 197 + src/pathfinder/yapf/yapf_costbase.hpp | 44 + src/pathfinder/yapf/yapf_costcache.hpp | 231 + src/pathfinder/yapf/yapf_costrail.hpp | 646 ++ src/pathfinder/yapf/yapf_destrail.hpp | 208 + src/pathfinder/yapf/yapf_node.hpp | 129 + src/pathfinder/yapf/yapf_node_rail.hpp | 228 + src/pathfinder/yapf/yapf_node_road.hpp | 39 + src/pathfinder/yapf/yapf_node_ship.hpp | 27 + src/pathfinder/yapf/yapf_rail.cpp | 647 ++ src/pathfinder/yapf/yapf_road.cpp | 533 + src/pathfinder/yapf/yapf_ship.cpp | 271 + src/pathfinder/yapf/yapf_type.hpp | 84 + src/pbs.cpp | 451 + src/pbs.h | 65 + src/progress.cpp | 46 + src/progress.h | 35 + src/querystring_gui.h | 97 + src/rail.cpp | 313 + src/rail.h | 448 + src/rail_cmd.cpp | 3089 ++++++ src/rail_gui.cpp | 2025 ++++ src/rail_gui.h | 24 + src/rail_map.h | 547 + src/rail_type.h | 63 + src/rev.cpp.in | 92 + src/rev.h | 24 + src/road.cpp | 154 + src/road_cmd.cpp | 1877 ++++ src/road_cmd.h | 21 + src/road_func.h | 184 + src/road_gui.cpp | 1158 ++ src/road_gui.h | 23 + src/road_internal.h | 24 + src/road_map.cpp | 61 + src/road_map.h | 613 ++ src/road_type.h | 76 + src/roadstop.cpp | 392 + src/roadstop_base.h | 196 + src/roadveh.h | 303 + src/roadveh_cmd.cpp | 1692 +++ src/roadveh_gui.cpp | 165 + src/safeguards.h | 74 + src/saveload/afterload.cpp | 3155 ++++++ src/saveload/ai_sl.cpp | 129 + src/saveload/airport_sl.cpp | 42 + src/saveload/animated_tile_sl.cpp | 62 + src/saveload/autoreplace_sl.cpp | 67 + src/saveload/cargomonitor_sl.cpp | 126 + src/saveload/cargopacket_sl.cpp | 143 + src/saveload/cheat_sl.cpp | 55 + src/saveload/company_sl.cpp | 545 + src/saveload/depot_sl.cpp | 68 + src/saveload/economy_sl.cpp | 108 + src/saveload/engine_sl.cpp | 202 + src/saveload/game_sl.cpp | 186 + src/saveload/gamelog_sl.cpp | 183 + src/saveload/goal_sl.cpp | 49 + src/saveload/group_sl.cpp | 65 + src/saveload/industry_sl.cpp | 190 + src/saveload/labelmaps_sl.cpp | 124 + src/saveload/linkgraph_sl.cpp | 298 + src/saveload/map_sl.cpp | 311 + src/saveload/misc_sl.cpp | 156 + src/saveload/newgrf_sl.cpp | 118 + src/saveload/newgrf_sl.h | 20 + src/saveload/object_sl.cpp | 79 + src/saveload/oldloader.cpp | 334 + src/saveload/oldloader.h | 137 + src/saveload/oldloader_sl.cpp | 1839 ++++ src/saveload/order_sl.cpp | 312 + src/saveload/saveload.cpp | 2891 +++++ src/saveload/saveload.h | 846 ++ src/saveload/saveload_filter.h | 107 + src/saveload/saveload_internal.h | 61 + src/saveload/signs_sl.cpp | 72 + src/saveload/station_sl.cpp | 644 ++ src/saveload/storage_sl.cpp | 54 + src/saveload/story_sl.cpp | 107 + src/saveload/strings_sl.cpp | 144 + src/saveload/subsidy_sl.cpp | 52 + src/saveload/town_sl.cpp | 325 + src/saveload/vehicle_sl.cpp | 962 ++ src/saveload/waypoint_sl.cpp | 217 + src/screenshot.cpp | 860 ++ src/screenshot.h | 38 + src/script/api/Doxyfile_AI | 250 + src/script/api/Doxyfile_Game | 250 + src/script/api/ai/ai_accounting.hpp.sq | 28 + src/script/api/ai/ai_airport.hpp.sq | 58 + src/script/api/ai/ai_base.hpp.sq | 32 + src/script/api/ai/ai_basestation.hpp.sq | 35 + src/script/api/ai/ai_bridge.hpp.sq | 50 + src/script/api/ai/ai_bridgelist.hpp.sq | 37 + src/script/api/ai/ai_cargo.hpp.sq | 57 + src/script/api/ai/ai_cargolist.hpp.sq | 61 + src/script/api/ai/ai_company.hpp.sq | 109 + src/script/api/ai/ai_controller.hpp.sq | 32 + src/script/api/ai/ai_date.hpp.sq | 34 + src/script/api/ai/ai_depotlist.hpp.sq | 25 + src/script/api/ai/ai_engine.hpp.sq | 51 + src/script/api/ai/ai_enginelist.hpp.sq | 25 + src/script/api/ai/ai_error.hpp.sq | 119 + src/script/api/ai/ai_event.hpp.sq | 72 + src/script/api/ai/ai_event_types.hpp.sq | 407 + src/script/api/ai/ai_execmode.hpp.sq | 25 + src/script/api/ai/ai_gamesettings.hpp.sq | 29 + src/script/api/ai/ai_group.hpp.sq | 50 + src/script/api/ai/ai_grouplist.hpp.sq | 25 + src/script/api/ai/ai_industry.hpp.sq | 49 + src/script/api/ai/ai_industrylist.hpp.sq | 49 + src/script/api/ai/ai_industrytype.hpp.sq | 44 + src/script/api/ai/ai_industrytypelist.hpp.sq | 25 + src/script/api/ai/ai_infrastructure.hpp.sq | 39 + src/script/api/ai/ai_list.hpp.sq | 64 + src/script/api/ai/ai_log.hpp.sq | 29 + src/script/api/ai/ai_map.hpp.sq | 39 + src/script/api/ai/ai_marine.hpp.sq | 53 + src/script/api/ai/ai_order.hpp.sq | 118 + src/script/api/ai/ai_rail.hpp.sq | 100 + src/script/api/ai/ai_railtypelist.hpp.sq | 25 + src/script/api/ai/ai_road.hpp.sq | 80 + src/script/api/ai/ai_sign.hpp.sq | 39 + src/script/api/ai/ai_signlist.hpp.sq | 25 + src/script/api/ai/ai_station.hpp.sq | 70 + src/script/api/ai/ai_stationlist.hpp.sq | 176 + src/script/api/ai/ai_subsidy.hpp.sq | 39 + src/script/api/ai/ai_subsidylist.hpp.sq | 25 + src/script/api/ai/ai_testmode.hpp.sq | 25 + src/script/api/ai/ai_tile.hpp.sq | 121 + src/script/api/ai/ai_tilelist.hpp.sq | 66 + src/script/api/ai/ai_town.hpp.sq | 83 + src/script/api/ai/ai_townlist.hpp.sq | 37 + src/script/api/ai/ai_tunnel.hpp.sq | 46 + src/script/api/ai/ai_vehicle.hpp.sq | 147 + src/script/api/ai/ai_vehiclelist.hpp.sq | 85 + src/script/api/ai/ai_waypoint.hpp.sq | 42 + src/script/api/ai/ai_waypointlist.hpp.sq | 37 + src/script/api/ai_changelog.hpp | 377 + src/script/api/doxygen_filter.awk | 292 + src/script/api/doxygen_filter.sh | 28 + src/script/api/game/game_accounting.hpp.sq | 28 + src/script/api/game/game_admin.hpp.sq | 27 + src/script/api/game/game_airport.hpp.sq | 58 + src/script/api/game/game_base.hpp.sq | 32 + src/script/api/game/game_basestation.hpp.sq | 35 + src/script/api/game/game_bridge.hpp.sq | 50 + src/script/api/game/game_bridgelist.hpp.sq | 37 + src/script/api/game/game_cargo.hpp.sq | 57 + src/script/api/game/game_cargolist.hpp.sq | 61 + src/script/api/game/game_cargomonitor.hpp.sq | 31 + src/script/api/game/game_client.hpp.sq | 34 + src/script/api/game/game_clientlist.hpp.sq | 37 + src/script/api/game/game_company.hpp.sq | 119 + src/script/api/game/game_companymode.hpp.sq | 25 + src/script/api/game/game_controller.hpp.sq | 32 + src/script/api/game/game_date.hpp.sq | 35 + src/script/api/game/game_depotlist.hpp.sq | 25 + src/script/api/game/game_engine.hpp.sq | 51 + src/script/api/game/game_enginelist.hpp.sq | 25 + src/script/api/game/game_error.hpp.sq | 119 + src/script/api/game/game_event.hpp.sq | 72 + src/script/api/game/game_event_types.hpp.sq | 312 + src/script/api/game/game_execmode.hpp.sq | 25 + src/script/api/game/game_game.hpp.sq | 36 + src/script/api/game/game_gamesettings.hpp.sq | 29 + src/script/api/game/game_goal.hpp.sq | 66 + src/script/api/game/game_industry.hpp.sq | 49 + src/script/api/game/game_industrylist.hpp.sq | 49 + src/script/api/game/game_industrytype.hpp.sq | 44 + .../api/game/game_industrytypelist.hpp.sq | 25 + .../api/game/game_infrastructure.hpp.sq | 39 + src/script/api/game/game_list.hpp.sq | 64 + src/script/api/game/game_log.hpp.sq | 29 + src/script/api/game/game_map.hpp.sq | 39 + src/script/api/game/game_marine.hpp.sq | 53 + src/script/api/game/game_news.hpp.sq | 40 + src/script/api/game/game_order.hpp.sq | 101 + src/script/api/game/game_rail.hpp.sq | 100 + src/script/api/game/game_railtypelist.hpp.sq | 25 + src/script/api/game/game_road.hpp.sq | 80 + src/script/api/game/game_sign.hpp.sq | 40 + src/script/api/game/game_signlist.hpp.sq | 25 + src/script/api/game/game_station.hpp.sq | 71 + src/script/api/game/game_stationlist.hpp.sq | 176 + src/script/api/game/game_story_page.hpp.sq | 46 + .../api/game/game_storypageelementlist.hpp.sq | 25 + src/script/api/game/game_storypagelist.hpp.sq | 25 + src/script/api/game/game_subsidy.hpp.sq | 40 + src/script/api/game/game_subsidylist.hpp.sq | 25 + src/script/api/game/game_testmode.hpp.sq | 25 + src/script/api/game/game_text.hpp.sq | 31 + src/script/api/game/game_tile.hpp.sq | 121 + src/script/api/game/game_tilelist.hpp.sq | 66 + src/script/api/game/game_town.hpp.sq | 88 + src/script/api/game/game_townlist.hpp.sq | 37 + src/script/api/game/game_tunnel.hpp.sq | 46 + src/script/api/game/game_vehicle.hpp.sq | 148 + src/script/api/game/game_vehiclelist.hpp.sq | 61 + src/script/api/game/game_viewport.hpp.sq | 30 + src/script/api/game/game_waypoint.hpp.sq | 42 + src/script/api/game/game_waypointlist.hpp.sq | 37 + src/script/api/game/game_window.hpp.sq | 1367 +++ src/script/api/game_changelog.hpp | 148 + src/script/api/generate_widget.awk | 116 + src/script/api/generate_widget.sh | 24 + src/script/api/generate_widget.vbs | 192 + src/script/api/script_accounting.cpp | 36 + src/script/api/script_accounting.hpp | 66 + src/script/api/script_admin.cpp | 150 + src/script/api/script_admin.hpp | 53 + src/script/api/script_airport.cpp | 172 + src/script/api/script_airport.hpp | 214 + src/script/api/script_base.cpp | 55 + src/script/api/script_base.hpp | 79 + src/script/api/script_basestation.cpp | 62 + src/script/api/script_basestation.hpp | 80 + src/script/api/script_bridge.cpp | 181 + src/script/api/script_bridge.hpp | 176 + src/script/api/script_bridgelist.cpp | 33 + src/script/api/script_bridgelist.hpp | 40 + src/script/api/script_cargo.cpp | 75 + src/script/api/script_cargo.hpp | 151 + src/script/api/script_cargolist.cpp | 64 + src/script/api/script_cargolist.hpp | 68 + src/script/api/script_cargomonitor.cpp | 69 + src/script/api/script_cargomonitor.hpp | 97 + src/script/api/script_client.cpp | 74 + src/script/api/script_client.hpp | 70 + src/script/api/script_clientlist.cpp | 49 + src/script/api/script_clientlist.hpp | 42 + src/script/api/script_company.cpp | 328 + src/script/api/script_company.hpp | 419 + src/script/api/script_companymode.cpp | 30 + src/script/api/script_companymode.hpp | 54 + src/script/api/script_controller.cpp | 187 + src/script/api/script_controller.hpp | 218 + src/script/api/script_date.cpp | 70 + src/script/api/script_date.hpp | 94 + src/script/api/script_depotlist.cpp | 48 + src/script/api/script_depotlist.hpp | 31 + src/script/api/script_engine.cpp | 268 + src/script/api/script_engine.hpp | 272 + src/script/api/script_enginelist.cpp | 24 + src/script/api/script_enginelist.hpp | 31 + src/script/api/script_error.cpp | 73 + src/script/api/script_error.hpp | 197 + src/script/api/script_event.cpp | 74 + src/script/api/script_event.hpp | 120 + src/script/api/script_event_types.cpp | 322 + src/script/api/script_event_types.hpp | 1063 ++ src/script/api/script_execmode.cpp | 46 + src/script/api/script_execmode.hpp | 56 + src/script/api/script_game.cpp | 47 + src/script/api/script_game.hpp | 68 + src/script/api/script_gamesettings.cpp | 62 + src/script/api/script_gamesettings.hpp | 84 + src/script/api/script_goal.cpp | 154 + src/script/api/script_goal.hpp | 217 + src/script/api/script_group.cpp | 196 + src/script/api/script_group.hpp | 219 + src/script/api/script_grouplist.cpp | 24 + src/script/api/script_grouplist.hpp | 28 + src/script/api/script_industry.cpp | 210 + src/script/api/script_industry.hpp | 203 + src/script/api/script_industrylist.cpp | 46 + src/script/api/script_industrylist.hpp | 54 + src/script/api/script_industrytype.cpp | 156 + src/script/api/script_industrytype.hpp | 188 + src/script/api/script_industrytypelist.cpp | 23 + src/script/api/script_industrytypelist.hpp | 28 + src/script/api/script_info_docs.hpp | 264 + src/script/api/script_infrastructure.cpp | 135 + src/script/api/script_infrastructure.hpp | 85 + src/script/api/script_list.cpp | 944 ++ src/script/api/script_list.hpp | 293 + src/script/api/script_log.cpp | 94 + src/script/api/script_log.hpp | 87 + src/script/api/script_map.cpp | 77 + src/script/api/script_map.hpp | 126 + src/script/api/script_marine.cpp | 174 + src/script/api/script_marine.hpp | 221 + src/script/api/script_news.cpp | 44 + src/script/api/script_news.hpp | 71 + src/script/api/script_object.cpp | 379 + src/script/api/script_object.hpp | 303 + src/script/api/script_order.cpp | 677 ++ src/script/api/script_order.hpp | 608 ++ src/script/api/script_rail.cpp | 510 + src/script/api/script_rail.hpp | 502 + src/script/api/script_railtypelist.cpp | 23 + src/script/api/script_railtypelist.hpp | 27 + src/script/api/script_road.cpp | 604 ++ src/script/api/script_road.hpp | 513 + src/script/api/script_sign.cpp | 85 + src/script/api/script_sign.hpp | 101 + src/script/api/script_signlist.cpp | 25 + src/script/api/script_signlist.hpp | 27 + src/script/api/script_station.cpp | 247 + src/script/api/script_station.hpp | 315 + src/script/api/script_stationlist.cpp | 275 + src/script/api/script_stationlist.hpp | 289 + src/script/api/script_story_page.cpp | 177 + src/script/api/script_story_page.hpp | 212 + .../api/script_storypageelementlist.cpp | 28 + .../api/script_storypageelementlist.hpp | 32 + src/script/api/script_storypagelist.cpp | 30 + src/script/api/script_storypagelist.hpp | 31 + src/script/api/script_subsidy.cpp | 101 + src/script/api/script_subsidy.hpp | 135 + src/script/api/script_subsidylist.cpp | 24 + src/script/api/script_subsidylist.hpp | 27 + src/script/api/script_testmode.cpp | 46 + src/script/api/script_testmode.hpp | 58 + src/script/api/script_text.cpp | 220 + src/script/api/script_text.hpp | 155 + src/script/api/script_tile.cpp | 323 + src/script/api/script_tile.hpp | 511 + src/script/api/script_tilelist.cpp | 137 + src/script/api/script_tilelist.hpp | 109 + src/script/api/script_town.cpp | 361 + src/script/api/script_town.hpp | 444 + src/script/api/script_townlist.cpp | 31 + src/script/api/script_townlist.hpp | 37 + src/script/api/script_tunnel.cpp | 138 + src/script/api/script_tunnel.hpp | 115 + src/script/api/script_types.hpp | 113 + src/script/api/script_vehicle.cpp | 461 + src/script/api/script_vehicle.hpp | 577 + src/script/api/script_vehiclelist.cpp | 132 + src/script/api/script_vehiclelist.hpp | 98 + src/script/api/script_viewport.cpp | 59 + src/script/api/script_viewport.hpp | 67 + src/script/api/script_waypoint.cpp | 39 + src/script/api/script_waypoint.hpp | 75 + src/script/api/script_waypointlist.cpp | 38 + src/script/api/script_waypointlist.hpp | 44 + src/script/api/script_window.cpp | 61 + src/script/api/script_window.hpp | 2649 +++++ src/script/api/squirrel_export.awk | 568 + src/script/api/squirrel_export.sh | 128 + src/script/api/squirrel_export.vbs | 946 ++ .../api/template/template_accounting.hpp.sq | 21 + src/script/api/template/template_admin.hpp.sq | 21 + .../api/template/template_airport.hpp.sq | 27 + src/script/api/template/template_base.hpp.sq | 21 + .../api/template/template_basestation.hpp.sq | 25 + .../api/template/template_bridge.hpp.sq | 25 + .../api/template/template_bridgelist.hpp.sq | 30 + src/script/api/template/template_cargo.hpp.sq | 31 + .../api/template/template_cargolist.hpp.sq | 48 + .../api/template/template_cargomonitor.hpp.sq | 21 + .../api/template/template_client.hpp.sq | 25 + .../api/template/template_clientlist.hpp.sq | 30 + .../api/template/template_company.hpp.sq | 35 + .../api/template/template_companymode.hpp.sq | 21 + src/script/api/template/template_date.hpp.sq | 25 + .../api/template/template_depotlist.hpp.sq | 21 + .../api/template/template_engine.hpp.sq | 21 + .../api/template/template_enginelist.hpp.sq | 21 + src/script/api/template/template_error.hpp.sq | 27 + src/script/api/template/template_event.hpp.sq | 34 + .../api/template/template_event_types.hpp.sq | 268 + .../api/template/template_execmode.hpp.sq | 21 + src/script/api/template/template_game.hpp.sq | 25 + .../api/template/template_gamesettings.hpp.sq | 21 + src/script/api/template/template_goal.hpp.sq | 31 + src/script/api/template/template_group.hpp.sq | 25 + .../api/template/template_grouplist.hpp.sq | 21 + .../api/template/template_industry.hpp.sq | 25 + .../api/template/template_industrylist.hpp.sq | 39 + .../api/template/template_industrytype.hpp.sq | 25 + .../template/template_industrytypelist.hpp.sq | 21 + .../template/template_infrastructure.hpp.sq | 25 + src/script/api/template/template_list.hpp.sq | 25 + src/script/api/template/template_log.hpp.sq | 21 + src/script/api/template/template_map.hpp.sq | 21 + .../api/template/template_marine.hpp.sq | 27 + src/script/api/template/template_news.hpp.sq | 27 + src/script/api/template/template_order.hpp.sq | 35 + src/script/api/template/template_rail.hpp.sq | 33 + .../api/template/template_railtypelist.hpp.sq | 21 + src/script/api/template/template_road.hpp.sq | 31 + src/script/api/template/template_sign.hpp.sq | 25 + .../api/template/template_signlist.hpp.sq | 21 + .../api/template/template_station.hpp.sq | 27 + .../api/template/template_stationlist.hpp.sq | 135 + .../api/template/template_story_page.hpp.sq | 29 + .../template_storypageelementlist.hpp.sq | 21 + .../template/template_storypagelist.hpp.sq | 21 + .../api/template/template_subsidy.hpp.sq | 25 + .../api/template/template_subsidylist.hpp.sq | 21 + .../api/template/template_testmode.hpp.sq | 21 + src/script/api/template/template_text.hpp.sq | 30 + src/script/api/template/template_tile.hpp.sq | 35 + .../api/template/template_tilelist.hpp.sq | 48 + src/script/api/template/template_town.hpp.sq | 33 + .../api/template/template_townlist.hpp.sq | 30 + .../api/template/template_tunnel.hpp.sq | 25 + .../api/template/template_vehicle.hpp.sq | 29 + .../api/template/template_vehiclelist.hpp.sq | 66 + .../api/template/template_viewport.hpp.sq | 21 + .../api/template/template_waypoint.hpp.sq | 27 + .../api/template/template_waypointlist.hpp.sq | 30 + .../api/template/template_window.hpp.sq | 263 + src/script/script_config.cpp | 215 + src/script/script_config.hpp | 211 + src/script/script_fatalerror.hpp | 38 + src/script/script_info.cpp | 311 + src/script/script_info.hpp | 171 + src/script/script_info_dummy.cpp | 112 + src/script/script_instance.cpp | 709 ++ src/script/script_instance.hpp | 272 + src/script/script_scanner.cpp | 291 + src/script/script_scanner.hpp | 137 + src/script/script_storage.hpp | 101 + src/script/script_suspend.hpp | 52 + src/script/squirrel.cpp | 609 ++ src/script/squirrel.hpp | 277 + src/script/squirrel_class.hpp | 132 + src/script/squirrel_helper.hpp | 913 ++ src/script/squirrel_helper_type.hpp | 21 + src/script/squirrel_std.cpp | 112 + src/script/squirrel_std.hpp | 65 + src/settings.cpp | 2288 ++++ src/settings_func.h | 50 + src/settings_gui.cpp | 2709 +++++ src/settings_gui.h | 33 + src/settings_internal.h | 133 + src/settings_type.h | 600 ++ src/settingsgen/settingsgen.cpp | 522 + src/ship.h | 68 + src/ship_cmd.cpp | 893 ++ src/ship_gui.cpp | 90 + src/signal.cpp | 664 ++ src/signal_func.h | 63 + src/signal_type.h | 51 + src/signs.cpp | 63 + src/signs_base.h | 40 + src/signs_cmd.cpp | 136 + src/signs_func.h | 31 + src/signs_gui.cpp | 589 + src/signs_type.h | 23 + src/slope_func.h | 423 + src/slope_type.h | 118 + src/smallmap_gui.cpp | 1868 ++++ src/smallmap_gui.h | 196 + src/sortlist_type.h | 404 + src/sound.cpp | 326 + src/sound/allegro_s.cpp | 93 + src/sound/allegro_s.h | 35 + src/sound/cocoa_s.cpp | 180 + src/sound/cocoa_s.h | 31 + src/sound/null_s.cpp | 18 + src/sound/null_s.h | 33 + src/sound/sdl_s.cpp | 69 + src/sound/sdl_s.h | 33 + src/sound/sound_driver.hpp | 33 + src/sound/win32_s.cpp | 112 + src/sound/win32_s.h | 33 + src/sound/xaudio2_s.cpp | 273 + src/sound/xaudio2_s.h | 33 + src/sound_func.h | 24 + src/sound_type.h | 124 + src/sprite.cpp | 133 + src/sprite.h | 179 + src/spritecache.cpp | 952 ++ src/spritecache.h | 61 + src/spriteloader/grf.cpp | 335 + src/spriteloader/grf.hpp | 25 + src/spriteloader/spriteloader.hpp | 69 + src/station.cpp | 567 + src/station_base.h | 543 + src/station_cmd.cpp | 4560 ++++++++ src/station_func.h | 68 + src/station_gui.cpp | 2419 +++++ src/station_gui.h | 33 + src/station_map.h | 668 ++ src/station_type.h | 111 + src/statusbar_gui.cpp | 273 + src/statusbar_gui.h | 28 + src/stdafx.h | 523 + src/story.cpp | 364 + src/story_base.h | 101 + src/story_gui.cpp | 772 ++ src/story_type.h | 28 + src/strgen/strgen.cpp | 587 + src/strgen/strgen.h | 151 + src/strgen/strgen_base.cpp | 1056 ++ src/string.cpp | 892 ++ src/string_base.h | 66 + src/string_func.h | 262 + src/string_type.h | 56 + src/stringfilter.cpp | 137 + src/stringfilter_type.h | 74 + src/strings.cpp | 2166 ++++ src/strings_func.h | 286 + src/strings_type.h | 101 + src/subsidy.cpp | 624 ++ src/subsidy_base.h | 66 + src/subsidy_func.h | 26 + src/subsidy_gui.cpp | 255 + src/subsidy_type.h | 31 + src/table/airport_defaults.h | 419 + src/table/airport_movement.h | 831 ++ src/table/airporttile_ids.h | 92 + src/table/airporttiles.h | 114 + src/table/animcursors.h | 93 + src/table/autorail.h | 81 + src/table/bridge_land.h | 801 ++ src/table/build_industry.h | 1852 ++++ src/table/cargo_const.h | 173 + src/table/clear_land.h | 78 + src/table/company_settings.ini | 139 + src/table/control_codes.h | 179 + src/table/currency_settings.ini | 69 + src/table/elrail_data.h | 513 + src/table/engines.h | 769 ++ src/table/gameopt_settings.ini | 186 + src/table/genland.h | 168 + src/table/heightmap_colours.h | 344 + src/table/industry_land.h | 958 ++ src/table/landscape_sprite.h | 145 + src/table/misc_settings.ini | 321 + src/table/newgrf_debug_data.h | 579 + src/table/object_land.h | 150 + src/table/palette_convert.h | 82 + src/table/palettes.h | 149 + src/table/pricebase.h | 85 + src/table/railtypes.h | 415 + src/table/road_land.h | 291 + src/table/roadveh_movement.h | 1486 +++ src/table/settings.h.postamble | 0 src/table/settings.h.preamble | 136 + src/table/settings.ini | 3966 +++++++ src/table/sprites.h | 1588 +++ src/table/station_land.h | 1004 ++ src/table/strgen_tables.h | 210 + src/table/string_colours.h | 31 + src/table/town_land.h | 2281 ++++ src/table/townname.h | 3317 ++++++ src/table/track_land.h | 54 + src/table/train_cmd.h | 70 + src/table/tree_land.h | 230 + src/table/unicode.h | 40 + src/table/water_land.h | 164 + src/table/win32_settings.ini | 61 + src/table/window_settings.ini | 55 + src/tar_type.h | 45 + src/terraform_cmd.cpp | 421 + src/terraform_gui.cpp | 755 ++ src/terraform_gui.h | 20 + src/textbuf.cpp | 508 + src/textbuf_gui.h | 45 + src/textbuf_type.h | 84 + src/texteff.cpp | 126 + src/texteff.hpp | 46 + src/textfile_gui.cpp | 426 + src/textfile_gui.h | 51 + src/textfile_type.h | 27 + src/tgp.cpp | 1015 ++ src/tgp.h | 17 + src/thread/thread.h | 126 + src/thread/thread_morphos.cpp | 197 + src/thread/thread_none.cpp | 35 + src/thread/thread_os2.cpp | 147 + src/thread/thread_pthread.cpp | 191 + src/thread/thread_win32.cpp | 167 + src/tile_cmd.h | 197 + src/tile_map.cpp | 156 + src/tile_map.h | 341 + src/tile_type.h | 87 + src/tilearea.cpp | 245 + src/tilearea_type.h | 234 + src/tilehighlight_func.h | 35 + src/tilehighlight_type.h | 83 + src/tilematrix_type.hpp | 146 + src/timetable.h | 22 + src/timetable_cmd.cpp | 484 + src/timetable_gui.cpp | 715 ++ src/toolbar_gui.cpp | 2608 +++++ src/toolbar_gui.h | 21 + src/town.h | 298 + src/town_cmd.cpp | 3561 ++++++ src/town_gui.cpp | 1212 +++ src/town_map.h | 369 + src/town_type.h | 128 + src/townname.cpp | 1072 ++ src/townname_func.h | 23 + src/townname_type.h | 48 + src/track_func.h | 738 ++ src/track_type.h | 129 + src/train.h | 341 + src/train_cmd.cpp | 4027 +++++++ src/train_gui.cpp | 471 + src/transparency.h | 129 + src/transparency_gui.cpp | 164 + src/transparency_gui.h | 17 + src/transport_type.h | 39 + src/tree_cmd.cpp | 817 ++ src/tree_gui.cpp | 249 + src/tree_map.h | 289 + src/tunnel_map.cpp | 74 + src/tunnel_map.h | 87 + src/tunnelbridge.h | 38 + src/tunnelbridge_cmd.cpp | 1920 ++++ src/tunnelbridge_map.h | 124 + src/vehicle.cpp | 2909 +++++ src/vehicle_base.h | 1176 ++ src/vehicle_cmd.cpp | 1092 ++ src/vehicle_func.h | 183 + src/vehicle_gui.cpp | 2919 +++++ src/vehicle_gui.h | 106 + src/vehicle_gui_base.h | 64 + src/vehicle_type.h | 98 + src/vehiclelist.cpp | 189 + src/vehiclelist.h | 61 + src/video/allegro_v.cpp | 570 + src/video/allegro_v.h | 46 + src/video/cocoa/cocoa_keys.h | 136 + src/video/cocoa/cocoa_v.h | 278 + src/video/cocoa/cocoa_v.mm | 1373 +++ src/video/cocoa/event.mm | 732 ++ src/video/cocoa/fullscreen.mm | 524 + src/video/cocoa/wnd_quartz.mm | 649 ++ src/video/cocoa/wnd_quickdraw.mm | 563 + src/video/dedicated_v.cpp | 324 + src/video/dedicated_v.h | 49 + src/video/null_v.cpp | 57 + src/video/null_v.h | 45 + src/video/sdl_v.cpp | 840 ++ src/video/sdl_v.h | 54 + src/video/video_driver.hpp | 109 + src/video/win32_v.cpp | 1352 +++ src/video/win32_v.h | 54 + src/viewport.cpp | 3166 ++++++ src/viewport_func.h | 97 + src/viewport_gui.cpp | 191 + src/viewport_sprite_sorter.h | 58 + src/viewport_sprite_sorter_sse4.cpp | 105 + src/viewport_type.h | 136 + src/void_cmd.cpp | 91 + src/void_map.h | 34 + src/water.h | 57 + src/water_cmd.cpp | 1335 +++ src/water_map.h | 482 + src/waypoint.cpp | 57 + src/waypoint_base.h | 76 + src/waypoint_cmd.cpp | 426 + src/waypoint_func.h | 25 + src/waypoint_gui.cpp | 184 + src/widget.cpp | 2908 +++++ src/widget_type.h | 1161 ++ src/widgets/ai_widget.h | 73 + src/widgets/airport_widget.h | 37 + src/widgets/autoreplace_widget.h | 43 + src/widgets/bootstrap_widget.h | 27 + src/widgets/bridge_widget.h | 24 + src/widgets/build_vehicle_widget.h | 31 + src/widgets/cheat_widget.h | 20 + src/widgets/company_widget.h | 197 + src/widgets/console_widget.h | 20 + src/widgets/date_widget.h | 23 + src/widgets/depot_widget.h | 37 + src/widgets/dock_widget.h | 36 + src/widgets/dropdown.cpp | 514 + src/widgets/dropdown_func.h | 23 + src/widgets/dropdown_type.h | 92 + src/widgets/dropdown_widget.h | 22 + src/widgets/engine_widget.h | 22 + src/widgets/error_widget.h | 22 + src/widgets/fios_widget.h | 37 + src/widgets/framerate_widget.h | 34 + src/widgets/genworld_widget.h | 87 + src/widgets/goal_widget.h | 33 + src/widgets/graph_widget.h | 70 + src/widgets/group_widget.h | 39 + src/widgets/highscore_widget.h | 20 + src/widgets/industry_widget.h | 51 + src/widgets/intro_widget.h | 40 + src/widgets/link_graph_legend_widget.h | 36 + src/widgets/main_widget.h | 20 + src/widgets/misc_widget.h | 57 + src/widgets/music_widget.h | 55 + src/widgets/network_chat_widget.h | 24 + src/widgets/network_content_widget.h | 51 + src/widgets/network_widget.h | 129 + src/widgets/newgrf_debug_widget.h | 45 + src/widgets/newgrf_widget.h | 79 + src/widgets/news_widget.h | 45 + src/widgets/object_widget.h | 30 + src/widgets/order_widget.h | 44 + src/widgets/osk_widget.h | 43 + src/widgets/rail_widget.h | 115 + src/widgets/road_widget.h | 57 + src/widgets/settings_widget.h | 72 + src/widgets/sign_widget.h | 37 + src/widgets/smallmap_widget.h | 39 + src/widgets/station_widget.h | 66 + src/widgets/statusbar_widget.h | 22 + src/widgets/story_widget.h | 26 + src/widgets/subsidy_widget.h | 22 + src/widgets/terraform_widget.h | 49 + src/widgets/timetable_widget.h | 36 + src/widgets/toolbar_widget.h | 79 + src/widgets/town_widget.h | 65 + src/widgets/transparency_widget.h | 34 + src/widgets/tree_widget.h | 33 + src/widgets/vehicle_widget.h | 77 + src/widgets/viewport_widget.h | 25 + src/widgets/waypoint_widget.h | 24 + src/window.cpp | 3625 +++++++ src/window_func.h | 60 + src/window_gui.h | 921 ++ src/window_type.h | 718 ++ src/zoom_func.h | 107 + src/zoom_type.h | 60 + 1630 files changed, 736605 insertions(+) create mode 100644 CONTRIBUTING.md create mode 100644 COPYING create mode 100644 Doxyfile create mode 100644 Makefile.bundle.in create mode 100644 Makefile.grf.in create mode 100644 Makefile.in create mode 100644 Makefile.lang.in create mode 100644 Makefile.msvc create mode 100644 Makefile.setting.in create mode 100644 Makefile.src.in create mode 100644 README.md create mode 100644 azure-pipelines-ci.yml create mode 100644 azure-pipelines-release-stable.yml create mode 100644 azure-pipelines-release.yml create mode 100755 azure-pipelines/changelog.sh create mode 100755 azure-pipelines/manifest.sh create mode 100644 azure-pipelines/templates/ci-git-rebase.yml create mode 100644 azure-pipelines/templates/ci-opengfx.yml create mode 100644 azure-pipelines/templates/linux-build.yml create mode 100644 azure-pipelines/templates/linux-claim-bundles.yml create mode 100644 azure-pipelines/templates/osx-build.yml create mode 100644 azure-pipelines/templates/osx-dependencies.yml create mode 100644 azure-pipelines/templates/release-bundles.yml create mode 100644 azure-pipelines/templates/release-fetch-source.yml create mode 100644 azure-pipelines/templates/release-manifest.yml create mode 100644 azure-pipelines/templates/release-prepare-source.yml create mode 100644 azure-pipelines/templates/release.yml create mode 100644 azure-pipelines/templates/windows-build.yml create mode 100644 azure-pipelines/templates/windows-dependencies.yml create mode 100644 azure-pipelines/templates/windows-dependency-nsis.yml create mode 100644 azure-pipelines/templates/windows-dependency-zip.yml create mode 100644 bin/ai/compat_0.7.nut create mode 100644 bin/ai/compat_1.0.nut create mode 100644 bin/ai/compat_1.1.nut create mode 100644 bin/ai/compat_1.2.nut create mode 100644 bin/ai/compat_1.3.nut create mode 100644 bin/ai/compat_1.4.nut create mode 100644 bin/ai/compat_1.5.nut create mode 100644 bin/ai/compat_1.6.nut create mode 100644 bin/ai/compat_1.7.nut create mode 100644 bin/ai/compat_1.8.nut create mode 100644 bin/ai/compat_1.9.nut create mode 100755 bin/ai/regression/completeness.sh create mode 100644 bin/ai/regression/empty.sav create mode 100644 bin/ai/regression/regression.cfg create mode 100644 bin/ai/regression/regression_info.nut create mode 100755 bin/ai/regression/run.sh create mode 100644 bin/ai/regression/run.vbs create mode 100644 bin/ai/regression/tst_regression/main.nut create mode 100644 bin/ai/regression/tst_regression/require.nut create mode 100644 bin/ai/regression/tst_regression/result.txt create mode 100644 bin/ai/regression/tst_stationlist/main.nut create mode 100644 bin/ai/regression/tst_stationlist/result.txt create mode 100644 bin/ai/regression/tst_stationlist/test.sav create mode 100644 bin/baseset/openttd.grf create mode 100644 bin/baseset/opntitle.dat create mode 100644 bin/baseset/orig_extra.grf create mode 100644 bin/game/compat_1.2.nut create mode 100644 bin/game/compat_1.3.nut create mode 100644 bin/game/compat_1.4.nut create mode 100644 bin/game/compat_1.5.nut create mode 100644 bin/game/compat_1.6.nut create mode 100644 bin/game/compat_1.7.nut create mode 100644 bin/game/compat_1.8.nut create mode 100644 bin/game/compat_1.9.nut create mode 100644 bin/scripts/autoexec.scr.example create mode 100644 bin/scripts/game_start.scr.example create mode 100644 bin/scripts/on_client.scr.example create mode 100644 bin/scripts/on_dedicated.scr.example create mode 100644 bin/scripts/on_server.scr.example create mode 100644 bin/scripts/on_server_connect.scr.example create mode 100644 bin/scripts/pre_dedicated.scr.example create mode 100644 bin/scripts/pre_server.scr.example create mode 100644 bin/scripts/readme.txt create mode 100644 changelog.txt create mode 100644 config.lib create mode 100755 configure create mode 100644 docs/HOWTO_compile_lang_files.txt create mode 100644 docs/Readme_OS2.txt create mode 100644 docs/Readme_Windows_MSVC.md create mode 100644 docs/admin_network.txt create mode 100644 docs/desync.txt create mode 100644 docs/elrail.svg create mode 100644 docs/elrail_tile.png create mode 100644 docs/elrail_track.png create mode 100644 docs/landscape.html create mode 100644 docs/landscape_externals.html create mode 100644 docs/landscape_grid.html create mode 100644 docs/linkgraph.txt create mode 100644 docs/multiplayer.txt create mode 100644 docs/obg_format.txt create mode 100644 docs/obm_format.txt create mode 100644 docs/obs_format.txt create mode 100644 docs/openttd.6 create mode 100644 docs/ottd-colourtext-palette.png create mode 100644 docs/palettes/openttd.gpl create mode 100644 docs/palettes/palette.act create mode 100644 docs/tileh.png create mode 100755 findversion.sh create mode 100644 known-bugs.txt create mode 100644 media/baseset/no_music.obm create mode 100644 media/baseset/no_sound.obs create mode 100644 media/baseset/orig_dos.obg create mode 100644 media/baseset/orig_dos.obm create mode 100644 media/baseset/orig_dos.obs create mode 100644 media/baseset/orig_dos_de.obg create mode 100644 media/baseset/orig_tto.obm create mode 100644 media/baseset/orig_win.obg create mode 100644 media/baseset/orig_win.obm create mode 100644 media/baseset/orig_win.obs create mode 100644 media/baseset/translations.awk create mode 100644 media/baseset/translations.vbs create mode 100644 media/extra_grf/2ccmap.nfo create mode 100644 media/extra_grf/airport_preview.nfo create mode 100644 media/extra_grf/airport_preview.png create mode 100644 media/extra_grf/airports.nfo create mode 100644 media/extra_grf/airports.png create mode 100644 media/extra_grf/airports_orig_extra.nfo create mode 100644 media/extra_grf/aqueduct.nfo create mode 100644 media/extra_grf/aqueduct.png create mode 100644 media/extra_grf/assemble_nfo.awk create mode 100644 media/extra_grf/autorail.nfo create mode 100644 media/extra_grf/autorail.png create mode 100644 media/extra_grf/canal_locks.png create mode 100644 media/extra_grf/canals.nfo create mode 100644 media/extra_grf/canals.png create mode 100644 media/extra_grf/canals_extra.nfo create mode 100644 media/extra_grf/chars.nfo create mode 100644 media/extra_grf/chars.png create mode 100644 media/extra_grf/chars_orig_extra.nfo create mode 100644 media/extra_grf/elrails.nfo create mode 100644 media/extra_grf/elrails.png create mode 100644 media/extra_grf/fix_graphics.nfo create mode 100644 media/extra_grf/fix_graphics.png create mode 100644 media/extra_grf/flags.nfo create mode 100644 media/extra_grf/flags.png create mode 100644 media/extra_grf/foundations.nfo create mode 100644 media/extra_grf/foundations.png create mode 100644 media/extra_grf/mono.nfo create mode 100644 media/extra_grf/mono.png create mode 100644 media/extra_grf/oneway.nfo create mode 100644 media/extra_grf/oneway.png create mode 100644 media/extra_grf/openttd.nfo create mode 100644 media/extra_grf/openttdgui.nfo create mode 100644 media/extra_grf/openttdgui.png create mode 100644 media/extra_grf/openttdgui_group_livery.png create mode 100644 media/extra_grf/orig_extra.nfo create mode 100644 media/extra_grf/palette.nfo create mode 100644 media/extra_grf/rivers/arctic.nfo create mode 100644 media/extra_grf/rivers/arctic_brown.png create mode 100644 media/extra_grf/rivers/arctic_snowy.png create mode 100644 media/extra_grf/rivers/rapids.nfo create mode 100644 media/extra_grf/rivers/rapids.png create mode 100644 media/extra_grf/rivers/temperate.nfo create mode 100644 media/extra_grf/rivers/temperate.png create mode 100644 media/extra_grf/rivers/toyland.nfo create mode 100644 media/extra_grf/rivers/toyland.png create mode 100644 media/extra_grf/rivers/tropic.nfo create mode 100644 media/extra_grf/rivers/tropic_desert.png create mode 100644 media/extra_grf/rivers/tropic_forest.png create mode 100644 media/extra_grf/roadstops.nfo create mode 100644 media/extra_grf/roadstops.png create mode 100644 media/extra_grf/shore.nfo create mode 100644 media/extra_grf/shore.png create mode 100644 media/extra_grf/signals.nfo create mode 100644 media/extra_grf/signals.png create mode 100644 media/extra_grf/sloped_tracks.nfo create mode 100644 media/extra_grf/sloped_tracks.png create mode 100644 media/extra_grf/tramtracks.nfo create mode 100644 media/extra_grf/tramtracks.png create mode 100644 media/extra_grf/tunnel_portals.nfo create mode 100644 media/extra_grf/tunnel_portals.png create mode 100644 media/openttd.128.png create mode 100644 media/openttd.16.png create mode 100644 media/openttd.256.png create mode 100644 media/openttd.32.bmp create mode 100644 media/openttd.32.png create mode 100644 media/openttd.32.xpm create mode 100644 media/openttd.48.png create mode 100644 media/openttd.64.png create mode 100644 media/openttd.64.xpm create mode 100644 media/openttd.desktop.filter.awk create mode 100644 media/openttd.desktop.in create mode 100644 media/openttd.desktop.translation.awk create mode 100644 media/openttd.ico create mode 100644 media/openttd.svg create mode 100644 os/debian/NEWS create mode 100644 os/debian/README.Debian create mode 100644 os/debian/changelog create mode 100644 os/debian/compat create mode 100644 os/debian/control create mode 100644 os/debian/copyright create mode 100644 os/debian/gbp.conf create mode 100644 os/debian/menu create mode 100644 os/debian/openttd-wrapper create mode 100644 os/debian/patches/run-openttd-wrapper.patch create mode 100644 os/debian/patches/series create mode 100755 os/debian/rules create mode 100644 os/debian/source/format create mode 100644 os/debian/watch create mode 100644 os/dos/cwsdpmi/README.licensing create mode 100644 os/dos/cwsdpmi/cwsdpmi.exe create mode 100644 os/dos/cwsdpmi/cwsdpmi.txt create mode 100644 os/dos/cwsdpmi/cwsdstub.exe create mode 100644 os/dos/exe2coff/README.licensing create mode 100644 os/dos/exe2coff/copying create mode 100644 os/dos/exe2coff/copying.dj create mode 100644 os/dos/exe2coff/copying.lib create mode 100644 os/dos/exe2coff/exe2coff.c create mode 100755 os/dos/make_dos_binary_selfcontained.sh create mode 100644 os/macosx/openttd.icns create mode 100755 os/macosx/plistgen.sh create mode 100644 os/macosx/splash.png create mode 100644 os/morphos/icons/OpenTTD.info create mode 100644 os/morphos/icons/docs.info create mode 100644 os/morphos/icons/document.info create mode 100644 os/morphos/icons/drawer.info create mode 100644 os/os2/build_lang.cmd create mode 100644 os/os2/dedicated.cmd create mode 100644 os/os2/installer/download_nosound.cmd create mode 100644 os/os2/installer/download_opengfx.cmd create mode 100644 os/os2/installer/download_opensfx.cmd create mode 100644 os/os2/installer/make_installer.cmd create mode 100644 os/os2/installer/openttd.wis create mode 100644 os/os2/installer/remove_nosound.cmd create mode 100644 os/os2/installer/remove_opengfx.cmd create mode 100644 os/os2/installer/remove_opensfx.cmd create mode 100644 os/os2/openttd.wpj create mode 100644 os/os2/svn_version.cmd create mode 100644 os/os2/svnver1.c create mode 100644 os/os2/svnver2.c create mode 100644 os/rpm/openttd-rpmlintrc create mode 100644 os/rpm/openttd.changes create mode 100644 os/rpm/openttd.spec create mode 100644 os/windows/installer/build_installers.bat create mode 100644 os/windows/installer/cdfinder.ini create mode 100644 os/windows/installer/install.nsi create mode 100644 os/windows/installer/top.bmp create mode 100644 os/windows/installer/version_win32.txt create mode 100644 os/windows/installer/version_win64.txt create mode 100644 os/windows/installer/version_win9x.txt create mode 100644 os/windows/installer/welcome.bmp create mode 100644 projects/basesets_vs140.vcxproj create mode 100644 projects/basesets_vs140.vcxproj.filters create mode 100644 projects/basesets_vs140.vcxproj.filters.in create mode 100644 projects/basesets_vs140.vcxproj.in create mode 100644 projects/basesets_vs141.vcxproj create mode 100644 projects/basesets_vs141.vcxproj.filters create mode 100644 projects/basesets_vs141.vcxproj.filters.in create mode 100644 projects/basesets_vs141.vcxproj.in create mode 100644 projects/basesets_vs142.vcxproj create mode 100644 projects/basesets_vs142.vcxproj.filters create mode 100644 projects/basesets_vs142.vcxproj.filters.in create mode 100644 projects/basesets_vs142.vcxproj.in create mode 100755 projects/determineversion.vbs create mode 100644 projects/dpi_aware.manifest create mode 100755 projects/gen-kdev4.sh create mode 100755 projects/generate create mode 100644 projects/generate.vbs create mode 100644 projects/generate_vs140.vcxproj create mode 100644 projects/generate_vs141.vcxproj create mode 100644 projects/generate_vs142.vcxproj create mode 100644 projects/langs_vs140.vcxproj create mode 100644 projects/langs_vs140.vcxproj.filters create mode 100644 projects/langs_vs140.vcxproj.filters.in create mode 100644 projects/langs_vs140.vcxproj.in create mode 100644 projects/langs_vs141.vcxproj create mode 100644 projects/langs_vs141.vcxproj.filters create mode 100644 projects/langs_vs141.vcxproj.filters.in create mode 100644 projects/langs_vs141.vcxproj.in create mode 100644 projects/langs_vs142.vcxproj create mode 100644 projects/langs_vs142.vcxproj.filters create mode 100644 projects/langs_vs142.vcxproj.filters.in create mode 100644 projects/langs_vs142.vcxproj.in create mode 100644 projects/openttd_vs140.sln create mode 100644 projects/openttd_vs140.vcxproj create mode 100644 projects/openttd_vs140.vcxproj.filters create mode 100644 projects/openttd_vs140.vcxproj.filters.in create mode 100644 projects/openttd_vs140.vcxproj.in create mode 100644 projects/openttd_vs141.sln create mode 100644 projects/openttd_vs141.vcxproj create mode 100644 projects/openttd_vs141.vcxproj.filters create mode 100644 projects/openttd_vs141.vcxproj.filters.in create mode 100644 projects/openttd_vs141.vcxproj.in create mode 100644 projects/openttd_vs142.sln create mode 100644 projects/openttd_vs142.vcxproj create mode 100644 projects/openttd_vs142.vcxproj.filters create mode 100644 projects/openttd_vs142.vcxproj.filters.in create mode 100644 projects/openttd_vs142.vcxproj.in create mode 100644 projects/os_versions.manifest create mode 100644 projects/regression.bat create mode 100644 projects/regression_vs140.vcxproj create mode 100644 projects/regression_vs141.vcxproj create mode 100644 projects/regression_vs142.vcxproj create mode 100644 projects/settings_vs140.vcxproj create mode 100644 projects/settings_vs140.vcxproj.filters create mode 100644 projects/settings_vs140.vcxproj.filters.in create mode 100644 projects/settings_vs140.vcxproj.in create mode 100644 projects/settings_vs141.vcxproj create mode 100644 projects/settings_vs141.vcxproj.filters create mode 100644 projects/settings_vs141.vcxproj.filters.in create mode 100644 projects/settings_vs141.vcxproj.in create mode 100644 projects/settings_vs142.vcxproj create mode 100644 projects/settings_vs142.vcxproj.filters create mode 100644 projects/settings_vs142.vcxproj.filters.in create mode 100644 projects/settings_vs142.vcxproj.in create mode 100644 projects/settingsgen_vs140.vcxproj create mode 100644 projects/settingsgen_vs140.vcxproj.filters create mode 100644 projects/settingsgen_vs141.vcxproj create mode 100644 projects/settingsgen_vs141.vcxproj.filters create mode 100644 projects/settingsgen_vs142.vcxproj create mode 100644 projects/settingsgen_vs142.vcxproj.filters create mode 100644 projects/strgen_vs140.vcxproj create mode 100644 projects/strgen_vs140.vcxproj.filters create mode 100644 projects/strgen_vs141.vcxproj create mode 100644 projects/strgen_vs141.vcxproj.filters create mode 100644 projects/strgen_vs142.vcxproj create mode 100644 projects/strgen_vs142.vcxproj.filters create mode 100644 projects/version_vs140.vcxproj create mode 100644 projects/version_vs141.vcxproj create mode 100644 projects/version_vs142.vcxproj create mode 100644 source.list create mode 100644 src/3rdparty/README.licensing create mode 100644 src/3rdparty/md5/md5.cpp create mode 100644 src/3rdparty/md5/md5.h create mode 100644 src/3rdparty/os2/getaddrinfo.c create mode 100644 src/3rdparty/os2/getaddrinfo.h create mode 100644 src/3rdparty/os2/getnameinfo.c create mode 100644 src/3rdparty/os2/getnameinfo.h create mode 100644 src/3rdparty/squirrel/COPYRIGHT create mode 100644 src/3rdparty/squirrel/README.OpenTTD create mode 100644 src/3rdparty/squirrel/include/sqstdaux.h create mode 100644 src/3rdparty/squirrel/include/sqstdmath.h create mode 100644 src/3rdparty/squirrel/include/sqstdstring.h create mode 100644 src/3rdparty/squirrel/include/squirrel.h create mode 100644 src/3rdparty/squirrel/sqstdlib/sqstdaux.cpp create mode 100644 src/3rdparty/squirrel/sqstdlib/sqstdmath.cpp create mode 100644 src/3rdparty/squirrel/sqstdlib/sqstdrex.cpp create mode 100644 src/3rdparty/squirrel/sqstdlib/sqstdstring.cpp create mode 100644 src/3rdparty/squirrel/squirrel/sqapi.cpp create mode 100644 src/3rdparty/squirrel/squirrel/sqarray.h create mode 100644 src/3rdparty/squirrel/squirrel/sqbaselib.cpp create mode 100644 src/3rdparty/squirrel/squirrel/sqclass.cpp create mode 100644 src/3rdparty/squirrel/squirrel/sqclass.h create mode 100644 src/3rdparty/squirrel/squirrel/sqclosure.h create mode 100644 src/3rdparty/squirrel/squirrel/sqcompiler.cpp create mode 100644 src/3rdparty/squirrel/squirrel/sqcompiler.h create mode 100644 src/3rdparty/squirrel/squirrel/sqdebug.cpp create mode 100644 src/3rdparty/squirrel/squirrel/sqfuncproto.h create mode 100644 src/3rdparty/squirrel/squirrel/sqfuncstate.cpp create mode 100644 src/3rdparty/squirrel/squirrel/sqfuncstate.h create mode 100644 src/3rdparty/squirrel/squirrel/sqlexer.cpp create mode 100644 src/3rdparty/squirrel/squirrel/sqlexer.h create mode 100644 src/3rdparty/squirrel/squirrel/sqmem.cpp create mode 100644 src/3rdparty/squirrel/squirrel/sqobject.cpp create mode 100644 src/3rdparty/squirrel/squirrel/sqobject.h create mode 100644 src/3rdparty/squirrel/squirrel/sqopcodes.h create mode 100644 src/3rdparty/squirrel/squirrel/sqpcheader.h create mode 100644 src/3rdparty/squirrel/squirrel/sqstate.cpp create mode 100644 src/3rdparty/squirrel/squirrel/sqstate.h create mode 100644 src/3rdparty/squirrel/squirrel/sqstring.h create mode 100644 src/3rdparty/squirrel/squirrel/sqtable.cpp create mode 100644 src/3rdparty/squirrel/squirrel/sqtable.h create mode 100644 src/3rdparty/squirrel/squirrel/squserdata.h create mode 100644 src/3rdparty/squirrel/squirrel/squtils.h create mode 100644 src/3rdparty/squirrel/squirrel/sqvm.cpp create mode 100644 src/3rdparty/squirrel/squirrel/sqvm.h create mode 100644 src/ai/ai.hpp create mode 100644 src/ai/ai_config.cpp create mode 100644 src/ai/ai_config.hpp create mode 100644 src/ai/ai_core.cpp create mode 100644 src/ai/ai_gui.cpp create mode 100644 src/ai/ai_gui.hpp create mode 100644 src/ai/ai_info.cpp create mode 100644 src/ai/ai_info.hpp create mode 100644 src/ai/ai_instance.cpp create mode 100644 src/ai/ai_instance.hpp create mode 100644 src/ai/ai_scanner.cpp create mode 100644 src/ai/ai_scanner.hpp create mode 100644 src/aircraft.h create mode 100644 src/aircraft_cmd.cpp create mode 100644 src/aircraft_gui.cpp create mode 100644 src/airport.cpp create mode 100644 src/airport.h create mode 100644 src/airport_gui.cpp create mode 100644 src/animated_tile.cpp create mode 100644 src/animated_tile_func.h create mode 100644 src/articulated_vehicles.cpp create mode 100644 src/articulated_vehicles.h create mode 100644 src/autoreplace.cpp create mode 100644 src/autoreplace_base.h create mode 100644 src/autoreplace_cmd.cpp create mode 100644 src/autoreplace_func.h create mode 100644 src/autoreplace_gui.cpp create mode 100644 src/autoreplace_gui.h create mode 100644 src/autoreplace_type.h create mode 100644 src/autoslope.h create mode 100644 src/base_consist.cpp create mode 100644 src/base_consist.h create mode 100644 src/base_media_base.h create mode 100644 src/base_media_func.h create mode 100644 src/base_station_base.h create mode 100644 src/blitter/32bpp_anim.cpp create mode 100644 src/blitter/32bpp_anim.hpp create mode 100644 src/blitter/32bpp_anim_sse2.cpp create mode 100644 src/blitter/32bpp_anim_sse2.hpp create mode 100644 src/blitter/32bpp_anim_sse4.cpp create mode 100644 src/blitter/32bpp_anim_sse4.hpp create mode 100644 src/blitter/32bpp_base.cpp create mode 100644 src/blitter/32bpp_base.hpp create mode 100644 src/blitter/32bpp_optimized.cpp create mode 100644 src/blitter/32bpp_optimized.hpp create mode 100644 src/blitter/32bpp_simple.cpp create mode 100644 src/blitter/32bpp_simple.hpp create mode 100644 src/blitter/32bpp_sse2.cpp create mode 100644 src/blitter/32bpp_sse2.hpp create mode 100644 src/blitter/32bpp_sse4.cpp create mode 100644 src/blitter/32bpp_sse4.hpp create mode 100644 src/blitter/32bpp_sse_func.hpp create mode 100644 src/blitter/32bpp_sse_type.h create mode 100644 src/blitter/32bpp_ssse3.cpp create mode 100644 src/blitter/32bpp_ssse3.hpp create mode 100644 src/blitter/8bpp_base.cpp create mode 100644 src/blitter/8bpp_base.hpp create mode 100644 src/blitter/8bpp_optimized.cpp create mode 100644 src/blitter/8bpp_optimized.hpp create mode 100644 src/blitter/8bpp_simple.cpp create mode 100644 src/blitter/8bpp_simple.hpp create mode 100644 src/blitter/base.hpp create mode 100644 src/blitter/common.hpp create mode 100644 src/blitter/factory.hpp create mode 100644 src/blitter/null.cpp create mode 100644 src/blitter/null.hpp create mode 100644 src/bmp.cpp create mode 100644 src/bmp.h create mode 100644 src/bootstrap_gui.cpp create mode 100644 src/bridge.h create mode 100644 src/bridge_gui.cpp create mode 100644 src/bridge_map.cpp create mode 100644 src/bridge_map.h create mode 100644 src/build_vehicle_gui.cpp create mode 100644 src/cargo_type.h create mode 100644 src/cargoaction.cpp create mode 100644 src/cargoaction.h create mode 100644 src/cargomonitor.cpp create mode 100644 src/cargomonitor.h create mode 100644 src/cargopacket.cpp create mode 100644 src/cargopacket.h create mode 100644 src/cargotype.cpp create mode 100644 src/cargotype.h create mode 100644 src/cheat.cpp create mode 100644 src/cheat_func.h create mode 100644 src/cheat_gui.cpp create mode 100644 src/cheat_type.h create mode 100644 src/clear_cmd.cpp create mode 100644 src/clear_func.h create mode 100644 src/clear_map.h create mode 100644 src/cmd_helper.h create mode 100644 src/command.cpp create mode 100644 src/command_func.h create mode 100644 src/command_type.h create mode 100644 src/company_base.h create mode 100644 src/company_cmd.cpp create mode 100644 src/company_func.h create mode 100644 src/company_gui.cpp create mode 100644 src/company_gui.h create mode 100644 src/company_manager_face.h create mode 100644 src/company_type.h create mode 100644 src/console.cpp create mode 100644 src/console_cmds.cpp create mode 100644 src/console_func.h create mode 100644 src/console_gui.cpp create mode 100644 src/console_gui.h create mode 100644 src/console_internal.h create mode 100644 src/console_type.h create mode 100644 src/core/alloc_func.cpp create mode 100644 src/core/alloc_func.hpp create mode 100644 src/core/alloc_type.hpp create mode 100644 src/core/backup_type.hpp create mode 100644 src/core/bitmath_func.cpp create mode 100644 src/core/bitmath_func.hpp create mode 100644 src/core/endian_func.hpp create mode 100644 src/core/endian_type.hpp create mode 100644 src/core/enum_type.hpp create mode 100644 src/core/geometry_func.cpp create mode 100644 src/core/geometry_func.hpp create mode 100644 src/core/geometry_type.hpp create mode 100644 src/core/math_func.cpp create mode 100644 src/core/math_func.hpp create mode 100644 src/core/mem_func.hpp create mode 100644 src/core/multimap.hpp create mode 100644 src/core/overflowsafe_type.hpp create mode 100644 src/core/pool_func.cpp create mode 100644 src/core/pool_func.hpp create mode 100644 src/core/pool_type.hpp create mode 100644 src/core/random_func.cpp create mode 100644 src/core/random_func.hpp create mode 100644 src/core/smallmap_type.hpp create mode 100644 src/core/smallmatrix_type.hpp create mode 100644 src/core/smallstack_type.hpp create mode 100644 src/core/smallvec_type.hpp create mode 100644 src/core/sort_func.hpp create mode 100644 src/core/string_compare_type.hpp create mode 100644 src/cpu.cpp create mode 100644 src/cpu.h create mode 100644 src/crashlog.cpp create mode 100644 src/crashlog.h create mode 100644 src/currency.cpp create mode 100644 src/currency.h create mode 100644 src/date.cpp create mode 100644 src/date_func.h create mode 100644 src/date_gui.cpp create mode 100644 src/date_gui.h create mode 100644 src/date_type.h create mode 100644 src/debug.cpp create mode 100644 src/debug.h create mode 100644 src/dedicated.cpp create mode 100644 src/depend/depend.cpp create mode 100644 src/depot.cpp create mode 100644 src/depot_base.h create mode 100644 src/depot_cmd.cpp create mode 100644 src/depot_func.h create mode 100644 src/depot_gui.cpp create mode 100644 src/depot_map.h create mode 100644 src/depot_type.h create mode 100644 src/direction_func.h create mode 100644 src/direction_type.h create mode 100644 src/disaster_vehicle.cpp create mode 100644 src/disaster_vehicle.h create mode 100644 src/dock_gui.cpp create mode 100644 src/driver.cpp create mode 100644 src/driver.h create mode 100644 src/economy.cpp create mode 100644 src/economy_base.h create mode 100644 src/economy_func.h create mode 100644 src/economy_type.h create mode 100644 src/effectvehicle.cpp create mode 100644 src/effectvehicle_base.h create mode 100644 src/effectvehicle_func.h create mode 100644 src/elrail.cpp create mode 100644 src/elrail_func.h create mode 100644 src/engine.cpp create mode 100644 src/engine_base.h create mode 100644 src/engine_func.h create mode 100644 src/engine_gui.cpp create mode 100644 src/engine_gui.h create mode 100644 src/engine_type.h create mode 100644 src/error.h create mode 100644 src/error_gui.cpp create mode 100644 src/fileio.cpp create mode 100644 src/fileio_func.h create mode 100644 src/fileio_type.h create mode 100644 src/fios.cpp create mode 100644 src/fios.h create mode 100644 src/fios_gui.cpp create mode 100644 src/fontcache.cpp create mode 100644 src/fontcache.h create mode 100644 src/fontdetection.cpp create mode 100644 src/fontdetection.h create mode 100644 src/framerate_gui.cpp create mode 100644 src/framerate_type.h create mode 100644 src/game/game.hpp create mode 100644 src/game/game_config.cpp create mode 100644 src/game/game_config.hpp create mode 100644 src/game/game_core.cpp create mode 100644 src/game/game_info.cpp create mode 100644 src/game/game_info.hpp create mode 100644 src/game/game_instance.cpp create mode 100644 src/game/game_instance.hpp create mode 100644 src/game/game_scanner.cpp create mode 100644 src/game/game_scanner.hpp create mode 100644 src/game/game_text.cpp create mode 100644 src/game/game_text.hpp create mode 100644 src/gamelog.cpp create mode 100644 src/gamelog.h create mode 100644 src/gamelog_internal.h create mode 100644 src/genworld.cpp create mode 100644 src/genworld.h create mode 100644 src/genworld_gui.cpp create mode 100644 src/gfx.cpp create mode 100644 src/gfx_func.h create mode 100644 src/gfx_layout.cpp create mode 100644 src/gfx_layout.h create mode 100644 src/gfx_type.h create mode 100644 src/gfxinit.cpp create mode 100644 src/gfxinit.h create mode 100644 src/goal.cpp create mode 100644 src/goal_base.h create mode 100644 src/goal_gui.cpp create mode 100644 src/goal_type.h create mode 100644 src/graph_gui.cpp create mode 100644 src/graph_gui.h create mode 100644 src/ground_vehicle.cpp create mode 100644 src/ground_vehicle.hpp create mode 100644 src/group.h create mode 100644 src/group_cmd.cpp create mode 100644 src/group_gui.cpp create mode 100644 src/group_gui.h create mode 100644 src/group_type.h create mode 100644 src/gui.h create mode 100644 src/guitimer_func.h create mode 100644 src/heightmap.cpp create mode 100644 src/heightmap.h create mode 100644 src/highscore.cpp create mode 100644 src/highscore.h create mode 100644 src/highscore_gui.cpp create mode 100644 src/hotkeys.cpp create mode 100644 src/hotkeys.h create mode 100644 src/house.h create mode 100644 src/house_type.h create mode 100644 src/industry.h create mode 100644 src/industry_cmd.cpp create mode 100644 src/industry_gui.cpp create mode 100644 src/industry_map.h create mode 100644 src/industry_type.h create mode 100644 src/industrytype.h create mode 100644 src/ini.cpp create mode 100644 src/ini_load.cpp create mode 100644 src/ini_type.h create mode 100644 src/intro_gui.cpp create mode 100644 src/landscape.cpp create mode 100644 src/landscape.h create mode 100644 src/landscape_type.h create mode 100644 src/lang/afrikaans.txt create mode 100644 src/lang/arabic_egypt.txt create mode 100644 src/lang/basque.txt create mode 100644 src/lang/belarusian.txt create mode 100644 src/lang/brazilian_portuguese.txt create mode 100644 src/lang/bulgarian.txt create mode 100644 src/lang/catalan.txt create mode 100644 src/lang/croatian.txt create mode 100644 src/lang/czech.txt create mode 100644 src/lang/danish.txt create mode 100644 src/lang/dutch.txt create mode 100644 src/lang/english.txt create mode 100644 src/lang/english_AU.txt create mode 100644 src/lang/english_US.txt create mode 100644 src/lang/esperanto.txt create mode 100644 src/lang/estonian.txt create mode 100644 src/lang/faroese.txt create mode 100644 src/lang/finnish.txt create mode 100644 src/lang/french.txt create mode 100644 src/lang/gaelic.txt create mode 100644 src/lang/galician.txt create mode 100644 src/lang/german.txt create mode 100644 src/lang/greek.txt create mode 100644 src/lang/hebrew.txt create mode 100644 src/lang/hungarian.txt create mode 100644 src/lang/icelandic.txt create mode 100644 src/lang/indonesian.txt create mode 100644 src/lang/irish.txt create mode 100644 src/lang/italian.txt create mode 100644 src/lang/japanese.txt create mode 100644 src/lang/korean.txt create mode 100644 src/lang/latin.txt create mode 100644 src/lang/latvian.txt create mode 100644 src/lang/lithuanian.txt create mode 100644 src/lang/luxembourgish.txt create mode 100644 src/lang/malay.txt create mode 100644 src/lang/norwegian_bokmal.txt create mode 100644 src/lang/norwegian_nynorsk.txt create mode 100644 src/lang/polish.txt create mode 100644 src/lang/portuguese.txt create mode 100644 src/lang/romanian.txt create mode 100644 src/lang/russian.txt create mode 100644 src/lang/serbian.txt create mode 100644 src/lang/simplified_chinese.txt create mode 100644 src/lang/slovak.txt create mode 100644 src/lang/slovenian.txt create mode 100644 src/lang/spanish.txt create mode 100644 src/lang/spanish_MX.txt create mode 100644 src/lang/swedish.txt create mode 100644 src/lang/tamil.txt create mode 100644 src/lang/thai.txt create mode 100644 src/lang/traditional_chinese.txt create mode 100644 src/lang/turkish.txt create mode 100644 src/lang/ukrainian.txt create mode 100644 src/lang/unfinished/chuvash.txt create mode 100644 src/lang/unfinished/frisian.txt create mode 100644 src/lang/unfinished/ido.txt create mode 100644 src/lang/unfinished/macedonian.txt create mode 100644 src/lang/unfinished/maltese.txt create mode 100644 src/lang/unfinished/marathi.txt create mode 100644 src/lang/unfinished/persian.txt create mode 100644 src/lang/unfinished/urdu.txt create mode 100644 src/lang/vietnamese.txt create mode 100644 src/lang/welsh.txt create mode 100644 src/language.h create mode 100644 src/linkgraph/demands.cpp create mode 100644 src/linkgraph/demands.h create mode 100644 src/linkgraph/flowmapper.cpp create mode 100644 src/linkgraph/flowmapper.h create mode 100644 src/linkgraph/init.h create mode 100644 src/linkgraph/linkgraph.cpp create mode 100644 src/linkgraph/linkgraph.h create mode 100644 src/linkgraph/linkgraph_base.h create mode 100644 src/linkgraph/linkgraph_gui.cpp create mode 100644 src/linkgraph/linkgraph_gui.h create mode 100644 src/linkgraph/linkgraph_type.h create mode 100644 src/linkgraph/linkgraphjob.cpp create mode 100644 src/linkgraph/linkgraphjob.h create mode 100644 src/linkgraph/linkgraphjob_base.h create mode 100644 src/linkgraph/linkgraphschedule.cpp create mode 100644 src/linkgraph/linkgraphschedule.h create mode 100644 src/linkgraph/mcf.cpp create mode 100644 src/linkgraph/mcf.h create mode 100644 src/linkgraph/refresh.cpp create mode 100644 src/linkgraph/refresh.h create mode 100644 src/livery.h create mode 100644 src/main_gui.cpp create mode 100644 src/map.cpp create mode 100644 src/map_func.h create mode 100644 src/map_type.h create mode 100644 src/misc.cpp create mode 100644 src/misc/array.hpp create mode 100644 src/misc/binaryheap.hpp create mode 100644 src/misc/blob.hpp create mode 100644 src/misc/countedobj.cpp create mode 100644 src/misc/countedptr.hpp create mode 100644 src/misc/dbg_helpers.cpp create mode 100644 src/misc/dbg_helpers.h create mode 100644 src/misc/fixedsizearray.hpp create mode 100644 src/misc/getoptdata.cpp create mode 100644 src/misc/getoptdata.h create mode 100644 src/misc/hashtable.hpp create mode 100644 src/misc/str.hpp create mode 100644 src/misc_cmd.cpp create mode 100644 src/misc_gui.cpp create mode 100644 src/mixer.cpp create mode 100644 src/mixer.h create mode 100644 src/music.cpp create mode 100644 src/music/allegro_m.cpp create mode 100644 src/music/allegro_m.h create mode 100644 src/music/bemidi.cpp create mode 100644 src/music/bemidi.h create mode 100644 src/music/cocoa_m.cpp create mode 100644 src/music/cocoa_m.h create mode 100644 src/music/dmusic.cpp create mode 100644 src/music/dmusic.h create mode 100644 src/music/extmidi.cpp create mode 100644 src/music/extmidi.h create mode 100644 src/music/fluidsynth.cpp create mode 100644 src/music/fluidsynth.h create mode 100644 src/music/libtimidity.cpp create mode 100644 src/music/libtimidity.h create mode 100644 src/music/midi.h create mode 100644 src/music/midifile.cpp create mode 100644 src/music/midifile.hpp create mode 100644 src/music/music_driver.hpp create mode 100644 src/music/null_m.cpp create mode 100644 src/music/null_m.h create mode 100644 src/music/os2_m.cpp create mode 100644 src/music/os2_m.h create mode 100644 src/music/qtmidi.cpp create mode 100644 src/music/qtmidi.h create mode 100644 src/music/win32_m.cpp create mode 100644 src/music/win32_m.h create mode 100644 src/music_gui.cpp create mode 100644 src/network/core/address.cpp create mode 100644 src/network/core/address.h create mode 100644 src/network/core/config.h create mode 100644 src/network/core/core.cpp create mode 100644 src/network/core/core.h create mode 100644 src/network/core/game.h create mode 100644 src/network/core/host.cpp create mode 100644 src/network/core/host.h create mode 100644 src/network/core/os_abstraction.h create mode 100644 src/network/core/packet.cpp create mode 100644 src/network/core/packet.h create mode 100644 src/network/core/tcp.cpp create mode 100644 src/network/core/tcp.h create mode 100644 src/network/core/tcp_admin.cpp create mode 100644 src/network/core/tcp_admin.h create mode 100644 src/network/core/tcp_connect.cpp create mode 100644 src/network/core/tcp_content.cpp create mode 100644 src/network/core/tcp_content.h create mode 100644 src/network/core/tcp_game.cpp create mode 100644 src/network/core/tcp_game.h create mode 100644 src/network/core/tcp_http.cpp create mode 100644 src/network/core/tcp_http.h create mode 100644 src/network/core/tcp_listen.h create mode 100644 src/network/core/udp.cpp create mode 100644 src/network/core/udp.h create mode 100644 src/network/network.cpp create mode 100644 src/network/network.h create mode 100644 src/network/network_admin.cpp create mode 100644 src/network/network_admin.h create mode 100644 src/network/network_base.h create mode 100644 src/network/network_chat_gui.cpp create mode 100644 src/network/network_client.cpp create mode 100644 src/network/network_client.h create mode 100644 src/network/network_command.cpp create mode 100644 src/network/network_content.cpp create mode 100644 src/network/network_content.h create mode 100644 src/network/network_content_gui.cpp create mode 100644 src/network/network_content_gui.h create mode 100644 src/network/network_func.h create mode 100644 src/network/network_gamelist.cpp create mode 100644 src/network/network_gamelist.h create mode 100644 src/network/network_gui.cpp create mode 100644 src/network/network_gui.h create mode 100644 src/network/network_internal.h create mode 100644 src/network/network_server.cpp create mode 100644 src/network/network_server.h create mode 100644 src/network/network_type.h create mode 100644 src/network/network_udp.cpp create mode 100644 src/network/network_udp.h create mode 100644 src/newgrf.cpp create mode 100644 src/newgrf.h create mode 100644 src/newgrf_airport.cpp create mode 100644 src/newgrf_airport.h create mode 100644 src/newgrf_airporttiles.cpp create mode 100644 src/newgrf_airporttiles.h create mode 100644 src/newgrf_animation_base.h create mode 100644 src/newgrf_animation_type.h create mode 100644 src/newgrf_callbacks.h create mode 100644 src/newgrf_canal.cpp create mode 100644 src/newgrf_canal.h create mode 100644 src/newgrf_cargo.cpp create mode 100644 src/newgrf_cargo.h create mode 100644 src/newgrf_class.h create mode 100644 src/newgrf_class_func.h create mode 100644 src/newgrf_commons.cpp create mode 100644 src/newgrf_commons.h create mode 100644 src/newgrf_config.cpp create mode 100644 src/newgrf_config.h create mode 100644 src/newgrf_debug.h create mode 100644 src/newgrf_debug_gui.cpp create mode 100644 src/newgrf_engine.cpp create mode 100644 src/newgrf_engine.h create mode 100644 src/newgrf_generic.cpp create mode 100644 src/newgrf_generic.h create mode 100644 src/newgrf_gui.cpp create mode 100644 src/newgrf_house.cpp create mode 100644 src/newgrf_house.h create mode 100644 src/newgrf_industries.cpp create mode 100644 src/newgrf_industries.h create mode 100644 src/newgrf_industrytiles.cpp create mode 100644 src/newgrf_industrytiles.h create mode 100644 src/newgrf_object.cpp create mode 100644 src/newgrf_object.h create mode 100644 src/newgrf_properties.h create mode 100644 src/newgrf_railtype.cpp create mode 100644 src/newgrf_railtype.h create mode 100644 src/newgrf_sound.cpp create mode 100644 src/newgrf_sound.h create mode 100644 src/newgrf_spritegroup.cpp create mode 100644 src/newgrf_spritegroup.h create mode 100644 src/newgrf_station.cpp create mode 100644 src/newgrf_station.h create mode 100644 src/newgrf_storage.cpp create mode 100644 src/newgrf_storage.h create mode 100644 src/newgrf_text.cpp create mode 100644 src/newgrf_text.h create mode 100644 src/newgrf_town.cpp create mode 100644 src/newgrf_town.h create mode 100644 src/newgrf_townname.cpp create mode 100644 src/newgrf_townname.h create mode 100644 src/news_func.h create mode 100644 src/news_gui.cpp create mode 100644 src/news_gui.h create mode 100644 src/news_type.h create mode 100644 src/object.h create mode 100644 src/object_base.h create mode 100644 src/object_cmd.cpp create mode 100644 src/object_gui.cpp create mode 100644 src/object_map.h create mode 100644 src/object_type.h create mode 100644 src/openttd.cpp create mode 100644 src/openttd.h create mode 100644 src/order_backup.cpp create mode 100644 src/order_backup.h create mode 100644 src/order_base.h create mode 100644 src/order_cmd.cpp create mode 100644 src/order_func.h create mode 100644 src/order_gui.cpp create mode 100644 src/order_type.h create mode 100644 src/os/macosx/G5_detector.cpp create mode 100644 src/os/macosx/crashlog_osx.cpp create mode 100644 src/os/macosx/macos.h create mode 100644 src/os/macosx/macos.mm create mode 100644 src/os/macosx/osx_stdafx.h create mode 100644 src/os/macosx/splash.cpp create mode 100644 src/os/macosx/splash.h create mode 100644 src/os/macosx/string_osx.cpp create mode 100644 src/os/macosx/string_osx.h create mode 100644 src/os/os2/os2.cpp create mode 100644 src/os/unix/crashlog_unix.cpp create mode 100644 src/os/unix/unix.cpp create mode 100644 src/os/windows/crashlog_win.cpp create mode 100644 src/os/windows/ottdres.rc.in create mode 100644 src/os/windows/string_uniscribe.cpp create mode 100644 src/os/windows/string_uniscribe.h create mode 100644 src/os/windows/win32.cpp create mode 100644 src/os/windows/win32.h create mode 100644 src/osk_gui.cpp create mode 100644 src/pathfinder/follow_track.hpp create mode 100644 src/pathfinder/npf/aystar.cpp create mode 100644 src/pathfinder/npf/aystar.h create mode 100644 src/pathfinder/npf/npf.cpp create mode 100644 src/pathfinder/npf/npf_func.h create mode 100644 src/pathfinder/npf/queue.cpp create mode 100644 src/pathfinder/npf/queue.h create mode 100644 src/pathfinder/opf/opf_ship.cpp create mode 100644 src/pathfinder/opf/opf_ship.h create mode 100644 src/pathfinder/pathfinder_func.h create mode 100644 src/pathfinder/pathfinder_type.h create mode 100644 src/pathfinder/pf_performance_timer.hpp create mode 100644 src/pathfinder/yapf/nodelist.hpp create mode 100644 src/pathfinder/yapf/yapf.h create mode 100644 src/pathfinder/yapf/yapf.hpp create mode 100644 src/pathfinder/yapf/yapf_base.hpp create mode 100644 src/pathfinder/yapf/yapf_cache.h create mode 100644 src/pathfinder/yapf/yapf_common.hpp create mode 100644 src/pathfinder/yapf/yapf_costbase.hpp create mode 100644 src/pathfinder/yapf/yapf_costcache.hpp create mode 100644 src/pathfinder/yapf/yapf_costrail.hpp create mode 100644 src/pathfinder/yapf/yapf_destrail.hpp create mode 100644 src/pathfinder/yapf/yapf_node.hpp create mode 100644 src/pathfinder/yapf/yapf_node_rail.hpp create mode 100644 src/pathfinder/yapf/yapf_node_road.hpp create mode 100644 src/pathfinder/yapf/yapf_node_ship.hpp create mode 100644 src/pathfinder/yapf/yapf_rail.cpp create mode 100644 src/pathfinder/yapf/yapf_road.cpp create mode 100644 src/pathfinder/yapf/yapf_ship.cpp create mode 100644 src/pathfinder/yapf/yapf_type.hpp create mode 100644 src/pbs.cpp create mode 100644 src/pbs.h create mode 100644 src/progress.cpp create mode 100644 src/progress.h create mode 100644 src/querystring_gui.h create mode 100644 src/rail.cpp create mode 100644 src/rail.h create mode 100644 src/rail_cmd.cpp create mode 100644 src/rail_gui.cpp create mode 100644 src/rail_gui.h create mode 100644 src/rail_map.h create mode 100644 src/rail_type.h create mode 100644 src/rev.cpp.in create mode 100644 src/rev.h create mode 100644 src/road.cpp create mode 100644 src/road_cmd.cpp create mode 100644 src/road_cmd.h create mode 100644 src/road_func.h create mode 100644 src/road_gui.cpp create mode 100644 src/road_gui.h create mode 100644 src/road_internal.h create mode 100644 src/road_map.cpp create mode 100644 src/road_map.h create mode 100644 src/road_type.h create mode 100644 src/roadstop.cpp create mode 100644 src/roadstop_base.h create mode 100644 src/roadveh.h create mode 100644 src/roadveh_cmd.cpp create mode 100644 src/roadveh_gui.cpp create mode 100644 src/safeguards.h create mode 100644 src/saveload/afterload.cpp create mode 100644 src/saveload/ai_sl.cpp create mode 100644 src/saveload/airport_sl.cpp create mode 100644 src/saveload/animated_tile_sl.cpp create mode 100644 src/saveload/autoreplace_sl.cpp create mode 100644 src/saveload/cargomonitor_sl.cpp create mode 100644 src/saveload/cargopacket_sl.cpp create mode 100644 src/saveload/cheat_sl.cpp create mode 100644 src/saveload/company_sl.cpp create mode 100644 src/saveload/depot_sl.cpp create mode 100644 src/saveload/economy_sl.cpp create mode 100644 src/saveload/engine_sl.cpp create mode 100644 src/saveload/game_sl.cpp create mode 100644 src/saveload/gamelog_sl.cpp create mode 100644 src/saveload/goal_sl.cpp create mode 100644 src/saveload/group_sl.cpp create mode 100644 src/saveload/industry_sl.cpp create mode 100644 src/saveload/labelmaps_sl.cpp create mode 100644 src/saveload/linkgraph_sl.cpp create mode 100644 src/saveload/map_sl.cpp create mode 100644 src/saveload/misc_sl.cpp create mode 100644 src/saveload/newgrf_sl.cpp create mode 100644 src/saveload/newgrf_sl.h create mode 100644 src/saveload/object_sl.cpp create mode 100644 src/saveload/oldloader.cpp create mode 100644 src/saveload/oldloader.h create mode 100644 src/saveload/oldloader_sl.cpp create mode 100644 src/saveload/order_sl.cpp create mode 100644 src/saveload/saveload.cpp create mode 100644 src/saveload/saveload.h create mode 100644 src/saveload/saveload_filter.h create mode 100644 src/saveload/saveload_internal.h create mode 100644 src/saveload/signs_sl.cpp create mode 100644 src/saveload/station_sl.cpp create mode 100644 src/saveload/storage_sl.cpp create mode 100644 src/saveload/story_sl.cpp create mode 100644 src/saveload/strings_sl.cpp create mode 100644 src/saveload/subsidy_sl.cpp create mode 100644 src/saveload/town_sl.cpp create mode 100644 src/saveload/vehicle_sl.cpp create mode 100644 src/saveload/waypoint_sl.cpp create mode 100644 src/screenshot.cpp create mode 100644 src/screenshot.h create mode 100644 src/script/api/Doxyfile_AI create mode 100644 src/script/api/Doxyfile_Game create mode 100644 src/script/api/ai/ai_accounting.hpp.sq create mode 100644 src/script/api/ai/ai_airport.hpp.sq create mode 100644 src/script/api/ai/ai_base.hpp.sq create mode 100644 src/script/api/ai/ai_basestation.hpp.sq create mode 100644 src/script/api/ai/ai_bridge.hpp.sq create mode 100644 src/script/api/ai/ai_bridgelist.hpp.sq create mode 100644 src/script/api/ai/ai_cargo.hpp.sq create mode 100644 src/script/api/ai/ai_cargolist.hpp.sq create mode 100644 src/script/api/ai/ai_company.hpp.sq create mode 100644 src/script/api/ai/ai_controller.hpp.sq create mode 100644 src/script/api/ai/ai_date.hpp.sq create mode 100644 src/script/api/ai/ai_depotlist.hpp.sq create mode 100644 src/script/api/ai/ai_engine.hpp.sq create mode 100644 src/script/api/ai/ai_enginelist.hpp.sq create mode 100644 src/script/api/ai/ai_error.hpp.sq create mode 100644 src/script/api/ai/ai_event.hpp.sq create mode 100644 src/script/api/ai/ai_event_types.hpp.sq create mode 100644 src/script/api/ai/ai_execmode.hpp.sq create mode 100644 src/script/api/ai/ai_gamesettings.hpp.sq create mode 100644 src/script/api/ai/ai_group.hpp.sq create mode 100644 src/script/api/ai/ai_grouplist.hpp.sq create mode 100644 src/script/api/ai/ai_industry.hpp.sq create mode 100644 src/script/api/ai/ai_industrylist.hpp.sq create mode 100644 src/script/api/ai/ai_industrytype.hpp.sq create mode 100644 src/script/api/ai/ai_industrytypelist.hpp.sq create mode 100644 src/script/api/ai/ai_infrastructure.hpp.sq create mode 100644 src/script/api/ai/ai_list.hpp.sq create mode 100644 src/script/api/ai/ai_log.hpp.sq create mode 100644 src/script/api/ai/ai_map.hpp.sq create mode 100644 src/script/api/ai/ai_marine.hpp.sq create mode 100644 src/script/api/ai/ai_order.hpp.sq create mode 100644 src/script/api/ai/ai_rail.hpp.sq create mode 100644 src/script/api/ai/ai_railtypelist.hpp.sq create mode 100644 src/script/api/ai/ai_road.hpp.sq create mode 100644 src/script/api/ai/ai_sign.hpp.sq create mode 100644 src/script/api/ai/ai_signlist.hpp.sq create mode 100644 src/script/api/ai/ai_station.hpp.sq create mode 100644 src/script/api/ai/ai_stationlist.hpp.sq create mode 100644 src/script/api/ai/ai_subsidy.hpp.sq create mode 100644 src/script/api/ai/ai_subsidylist.hpp.sq create mode 100644 src/script/api/ai/ai_testmode.hpp.sq create mode 100644 src/script/api/ai/ai_tile.hpp.sq create mode 100644 src/script/api/ai/ai_tilelist.hpp.sq create mode 100644 src/script/api/ai/ai_town.hpp.sq create mode 100644 src/script/api/ai/ai_townlist.hpp.sq create mode 100644 src/script/api/ai/ai_tunnel.hpp.sq create mode 100644 src/script/api/ai/ai_vehicle.hpp.sq create mode 100644 src/script/api/ai/ai_vehiclelist.hpp.sq create mode 100644 src/script/api/ai/ai_waypoint.hpp.sq create mode 100644 src/script/api/ai/ai_waypointlist.hpp.sq create mode 100644 src/script/api/ai_changelog.hpp create mode 100644 src/script/api/doxygen_filter.awk create mode 100755 src/script/api/doxygen_filter.sh create mode 100644 src/script/api/game/game_accounting.hpp.sq create mode 100644 src/script/api/game/game_admin.hpp.sq create mode 100644 src/script/api/game/game_airport.hpp.sq create mode 100644 src/script/api/game/game_base.hpp.sq create mode 100644 src/script/api/game/game_basestation.hpp.sq create mode 100644 src/script/api/game/game_bridge.hpp.sq create mode 100644 src/script/api/game/game_bridgelist.hpp.sq create mode 100644 src/script/api/game/game_cargo.hpp.sq create mode 100644 src/script/api/game/game_cargolist.hpp.sq create mode 100644 src/script/api/game/game_cargomonitor.hpp.sq create mode 100644 src/script/api/game/game_client.hpp.sq create mode 100644 src/script/api/game/game_clientlist.hpp.sq create mode 100644 src/script/api/game/game_company.hpp.sq create mode 100644 src/script/api/game/game_companymode.hpp.sq create mode 100644 src/script/api/game/game_controller.hpp.sq create mode 100644 src/script/api/game/game_date.hpp.sq create mode 100644 src/script/api/game/game_depotlist.hpp.sq create mode 100644 src/script/api/game/game_engine.hpp.sq create mode 100644 src/script/api/game/game_enginelist.hpp.sq create mode 100644 src/script/api/game/game_error.hpp.sq create mode 100644 src/script/api/game/game_event.hpp.sq create mode 100644 src/script/api/game/game_event_types.hpp.sq create mode 100644 src/script/api/game/game_execmode.hpp.sq create mode 100644 src/script/api/game/game_game.hpp.sq create mode 100644 src/script/api/game/game_gamesettings.hpp.sq create mode 100644 src/script/api/game/game_goal.hpp.sq create mode 100644 src/script/api/game/game_industry.hpp.sq create mode 100644 src/script/api/game/game_industrylist.hpp.sq create mode 100644 src/script/api/game/game_industrytype.hpp.sq create mode 100644 src/script/api/game/game_industrytypelist.hpp.sq create mode 100644 src/script/api/game/game_infrastructure.hpp.sq create mode 100644 src/script/api/game/game_list.hpp.sq create mode 100644 src/script/api/game/game_log.hpp.sq create mode 100644 src/script/api/game/game_map.hpp.sq create mode 100644 src/script/api/game/game_marine.hpp.sq create mode 100644 src/script/api/game/game_news.hpp.sq create mode 100644 src/script/api/game/game_order.hpp.sq create mode 100644 src/script/api/game/game_rail.hpp.sq create mode 100644 src/script/api/game/game_railtypelist.hpp.sq create mode 100644 src/script/api/game/game_road.hpp.sq create mode 100644 src/script/api/game/game_sign.hpp.sq create mode 100644 src/script/api/game/game_signlist.hpp.sq create mode 100644 src/script/api/game/game_station.hpp.sq create mode 100644 src/script/api/game/game_stationlist.hpp.sq create mode 100644 src/script/api/game/game_story_page.hpp.sq create mode 100644 src/script/api/game/game_storypageelementlist.hpp.sq create mode 100644 src/script/api/game/game_storypagelist.hpp.sq create mode 100644 src/script/api/game/game_subsidy.hpp.sq create mode 100644 src/script/api/game/game_subsidylist.hpp.sq create mode 100644 src/script/api/game/game_testmode.hpp.sq create mode 100644 src/script/api/game/game_text.hpp.sq create mode 100644 src/script/api/game/game_tile.hpp.sq create mode 100644 src/script/api/game/game_tilelist.hpp.sq create mode 100644 src/script/api/game/game_town.hpp.sq create mode 100644 src/script/api/game/game_townlist.hpp.sq create mode 100644 src/script/api/game/game_tunnel.hpp.sq create mode 100644 src/script/api/game/game_vehicle.hpp.sq create mode 100644 src/script/api/game/game_vehiclelist.hpp.sq create mode 100644 src/script/api/game/game_viewport.hpp.sq create mode 100644 src/script/api/game/game_waypoint.hpp.sq create mode 100644 src/script/api/game/game_waypointlist.hpp.sq create mode 100644 src/script/api/game/game_window.hpp.sq create mode 100644 src/script/api/game_changelog.hpp create mode 100644 src/script/api/generate_widget.awk create mode 100755 src/script/api/generate_widget.sh create mode 100644 src/script/api/generate_widget.vbs create mode 100644 src/script/api/script_accounting.cpp create mode 100644 src/script/api/script_accounting.hpp create mode 100644 src/script/api/script_admin.cpp create mode 100644 src/script/api/script_admin.hpp create mode 100644 src/script/api/script_airport.cpp create mode 100644 src/script/api/script_airport.hpp create mode 100644 src/script/api/script_base.cpp create mode 100644 src/script/api/script_base.hpp create mode 100644 src/script/api/script_basestation.cpp create mode 100644 src/script/api/script_basestation.hpp create mode 100644 src/script/api/script_bridge.cpp create mode 100644 src/script/api/script_bridge.hpp create mode 100644 src/script/api/script_bridgelist.cpp create mode 100644 src/script/api/script_bridgelist.hpp create mode 100644 src/script/api/script_cargo.cpp create mode 100644 src/script/api/script_cargo.hpp create mode 100644 src/script/api/script_cargolist.cpp create mode 100644 src/script/api/script_cargolist.hpp create mode 100644 src/script/api/script_cargomonitor.cpp create mode 100644 src/script/api/script_cargomonitor.hpp create mode 100644 src/script/api/script_client.cpp create mode 100644 src/script/api/script_client.hpp create mode 100644 src/script/api/script_clientlist.cpp create mode 100644 src/script/api/script_clientlist.hpp create mode 100644 src/script/api/script_company.cpp create mode 100644 src/script/api/script_company.hpp create mode 100644 src/script/api/script_companymode.cpp create mode 100644 src/script/api/script_companymode.hpp create mode 100644 src/script/api/script_controller.cpp create mode 100644 src/script/api/script_controller.hpp create mode 100644 src/script/api/script_date.cpp create mode 100644 src/script/api/script_date.hpp create mode 100644 src/script/api/script_depotlist.cpp create mode 100644 src/script/api/script_depotlist.hpp create mode 100644 src/script/api/script_engine.cpp create mode 100644 src/script/api/script_engine.hpp create mode 100644 src/script/api/script_enginelist.cpp create mode 100644 src/script/api/script_enginelist.hpp create mode 100644 src/script/api/script_error.cpp create mode 100644 src/script/api/script_error.hpp create mode 100644 src/script/api/script_event.cpp create mode 100644 src/script/api/script_event.hpp create mode 100644 src/script/api/script_event_types.cpp create mode 100644 src/script/api/script_event_types.hpp create mode 100644 src/script/api/script_execmode.cpp create mode 100644 src/script/api/script_execmode.hpp create mode 100644 src/script/api/script_game.cpp create mode 100644 src/script/api/script_game.hpp create mode 100644 src/script/api/script_gamesettings.cpp create mode 100644 src/script/api/script_gamesettings.hpp create mode 100644 src/script/api/script_goal.cpp create mode 100644 src/script/api/script_goal.hpp create mode 100644 src/script/api/script_group.cpp create mode 100644 src/script/api/script_group.hpp create mode 100644 src/script/api/script_grouplist.cpp create mode 100644 src/script/api/script_grouplist.hpp create mode 100644 src/script/api/script_industry.cpp create mode 100644 src/script/api/script_industry.hpp create mode 100644 src/script/api/script_industrylist.cpp create mode 100644 src/script/api/script_industrylist.hpp create mode 100644 src/script/api/script_industrytype.cpp create mode 100644 src/script/api/script_industrytype.hpp create mode 100644 src/script/api/script_industrytypelist.cpp create mode 100644 src/script/api/script_industrytypelist.hpp create mode 100644 src/script/api/script_info_docs.hpp create mode 100644 src/script/api/script_infrastructure.cpp create mode 100644 src/script/api/script_infrastructure.hpp create mode 100644 src/script/api/script_list.cpp create mode 100644 src/script/api/script_list.hpp create mode 100644 src/script/api/script_log.cpp create mode 100644 src/script/api/script_log.hpp create mode 100644 src/script/api/script_map.cpp create mode 100644 src/script/api/script_map.hpp create mode 100644 src/script/api/script_marine.cpp create mode 100644 src/script/api/script_marine.hpp create mode 100644 src/script/api/script_news.cpp create mode 100644 src/script/api/script_news.hpp create mode 100644 src/script/api/script_object.cpp create mode 100644 src/script/api/script_object.hpp create mode 100644 src/script/api/script_order.cpp create mode 100644 src/script/api/script_order.hpp create mode 100644 src/script/api/script_rail.cpp create mode 100644 src/script/api/script_rail.hpp create mode 100644 src/script/api/script_railtypelist.cpp create mode 100644 src/script/api/script_railtypelist.hpp create mode 100644 src/script/api/script_road.cpp create mode 100644 src/script/api/script_road.hpp create mode 100644 src/script/api/script_sign.cpp create mode 100644 src/script/api/script_sign.hpp create mode 100644 src/script/api/script_signlist.cpp create mode 100644 src/script/api/script_signlist.hpp create mode 100644 src/script/api/script_station.cpp create mode 100644 src/script/api/script_station.hpp create mode 100644 src/script/api/script_stationlist.cpp create mode 100644 src/script/api/script_stationlist.hpp create mode 100644 src/script/api/script_story_page.cpp create mode 100644 src/script/api/script_story_page.hpp create mode 100644 src/script/api/script_storypageelementlist.cpp create mode 100644 src/script/api/script_storypageelementlist.hpp create mode 100644 src/script/api/script_storypagelist.cpp create mode 100644 src/script/api/script_storypagelist.hpp create mode 100644 src/script/api/script_subsidy.cpp create mode 100644 src/script/api/script_subsidy.hpp create mode 100644 src/script/api/script_subsidylist.cpp create mode 100644 src/script/api/script_subsidylist.hpp create mode 100644 src/script/api/script_testmode.cpp create mode 100644 src/script/api/script_testmode.hpp create mode 100644 src/script/api/script_text.cpp create mode 100644 src/script/api/script_text.hpp create mode 100644 src/script/api/script_tile.cpp create mode 100644 src/script/api/script_tile.hpp create mode 100644 src/script/api/script_tilelist.cpp create mode 100644 src/script/api/script_tilelist.hpp create mode 100644 src/script/api/script_town.cpp create mode 100644 src/script/api/script_town.hpp create mode 100644 src/script/api/script_townlist.cpp create mode 100644 src/script/api/script_townlist.hpp create mode 100644 src/script/api/script_tunnel.cpp create mode 100644 src/script/api/script_tunnel.hpp create mode 100644 src/script/api/script_types.hpp create mode 100644 src/script/api/script_vehicle.cpp create mode 100644 src/script/api/script_vehicle.hpp create mode 100644 src/script/api/script_vehiclelist.cpp create mode 100644 src/script/api/script_vehiclelist.hpp create mode 100644 src/script/api/script_viewport.cpp create mode 100644 src/script/api/script_viewport.hpp create mode 100644 src/script/api/script_waypoint.cpp create mode 100644 src/script/api/script_waypoint.hpp create mode 100644 src/script/api/script_waypointlist.cpp create mode 100644 src/script/api/script_waypointlist.hpp create mode 100644 src/script/api/script_window.cpp create mode 100644 src/script/api/script_window.hpp create mode 100644 src/script/api/squirrel_export.awk create mode 100755 src/script/api/squirrel_export.sh create mode 100644 src/script/api/squirrel_export.vbs create mode 100644 src/script/api/template/template_accounting.hpp.sq create mode 100644 src/script/api/template/template_admin.hpp.sq create mode 100644 src/script/api/template/template_airport.hpp.sq create mode 100644 src/script/api/template/template_base.hpp.sq create mode 100644 src/script/api/template/template_basestation.hpp.sq create mode 100644 src/script/api/template/template_bridge.hpp.sq create mode 100644 src/script/api/template/template_bridgelist.hpp.sq create mode 100644 src/script/api/template/template_cargo.hpp.sq create mode 100644 src/script/api/template/template_cargolist.hpp.sq create mode 100644 src/script/api/template/template_cargomonitor.hpp.sq create mode 100644 src/script/api/template/template_client.hpp.sq create mode 100644 src/script/api/template/template_clientlist.hpp.sq create mode 100644 src/script/api/template/template_company.hpp.sq create mode 100644 src/script/api/template/template_companymode.hpp.sq create mode 100644 src/script/api/template/template_date.hpp.sq create mode 100644 src/script/api/template/template_depotlist.hpp.sq create mode 100644 src/script/api/template/template_engine.hpp.sq create mode 100644 src/script/api/template/template_enginelist.hpp.sq create mode 100644 src/script/api/template/template_error.hpp.sq create mode 100644 src/script/api/template/template_event.hpp.sq create mode 100644 src/script/api/template/template_event_types.hpp.sq create mode 100644 src/script/api/template/template_execmode.hpp.sq create mode 100644 src/script/api/template/template_game.hpp.sq create mode 100644 src/script/api/template/template_gamesettings.hpp.sq create mode 100644 src/script/api/template/template_goal.hpp.sq create mode 100644 src/script/api/template/template_group.hpp.sq create mode 100644 src/script/api/template/template_grouplist.hpp.sq create mode 100644 src/script/api/template/template_industry.hpp.sq create mode 100644 src/script/api/template/template_industrylist.hpp.sq create mode 100644 src/script/api/template/template_industrytype.hpp.sq create mode 100644 src/script/api/template/template_industrytypelist.hpp.sq create mode 100644 src/script/api/template/template_infrastructure.hpp.sq create mode 100644 src/script/api/template/template_list.hpp.sq create mode 100644 src/script/api/template/template_log.hpp.sq create mode 100644 src/script/api/template/template_map.hpp.sq create mode 100644 src/script/api/template/template_marine.hpp.sq create mode 100644 src/script/api/template/template_news.hpp.sq create mode 100644 src/script/api/template/template_order.hpp.sq create mode 100644 src/script/api/template/template_rail.hpp.sq create mode 100644 src/script/api/template/template_railtypelist.hpp.sq create mode 100644 src/script/api/template/template_road.hpp.sq create mode 100644 src/script/api/template/template_sign.hpp.sq create mode 100644 src/script/api/template/template_signlist.hpp.sq create mode 100644 src/script/api/template/template_station.hpp.sq create mode 100644 src/script/api/template/template_stationlist.hpp.sq create mode 100644 src/script/api/template/template_story_page.hpp.sq create mode 100644 src/script/api/template/template_storypageelementlist.hpp.sq create mode 100644 src/script/api/template/template_storypagelist.hpp.sq create mode 100644 src/script/api/template/template_subsidy.hpp.sq create mode 100644 src/script/api/template/template_subsidylist.hpp.sq create mode 100644 src/script/api/template/template_testmode.hpp.sq create mode 100644 src/script/api/template/template_text.hpp.sq create mode 100644 src/script/api/template/template_tile.hpp.sq create mode 100644 src/script/api/template/template_tilelist.hpp.sq create mode 100644 src/script/api/template/template_town.hpp.sq create mode 100644 src/script/api/template/template_townlist.hpp.sq create mode 100644 src/script/api/template/template_tunnel.hpp.sq create mode 100644 src/script/api/template/template_vehicle.hpp.sq create mode 100644 src/script/api/template/template_vehiclelist.hpp.sq create mode 100644 src/script/api/template/template_viewport.hpp.sq create mode 100644 src/script/api/template/template_waypoint.hpp.sq create mode 100644 src/script/api/template/template_waypointlist.hpp.sq create mode 100644 src/script/api/template/template_window.hpp.sq create mode 100644 src/script/script_config.cpp create mode 100644 src/script/script_config.hpp create mode 100644 src/script/script_fatalerror.hpp create mode 100644 src/script/script_info.cpp create mode 100644 src/script/script_info.hpp create mode 100644 src/script/script_info_dummy.cpp create mode 100644 src/script/script_instance.cpp create mode 100644 src/script/script_instance.hpp create mode 100644 src/script/script_scanner.cpp create mode 100644 src/script/script_scanner.hpp create mode 100644 src/script/script_storage.hpp create mode 100644 src/script/script_suspend.hpp create mode 100644 src/script/squirrel.cpp create mode 100644 src/script/squirrel.hpp create mode 100644 src/script/squirrel_class.hpp create mode 100644 src/script/squirrel_helper.hpp create mode 100644 src/script/squirrel_helper_type.hpp create mode 100644 src/script/squirrel_std.cpp create mode 100644 src/script/squirrel_std.hpp create mode 100644 src/settings.cpp create mode 100644 src/settings_func.h create mode 100644 src/settings_gui.cpp create mode 100644 src/settings_gui.h create mode 100644 src/settings_internal.h create mode 100644 src/settings_type.h create mode 100644 src/settingsgen/settingsgen.cpp create mode 100644 src/ship.h create mode 100644 src/ship_cmd.cpp create mode 100644 src/ship_gui.cpp create mode 100644 src/signal.cpp create mode 100644 src/signal_func.h create mode 100644 src/signal_type.h create mode 100644 src/signs.cpp create mode 100644 src/signs_base.h create mode 100644 src/signs_cmd.cpp create mode 100644 src/signs_func.h create mode 100644 src/signs_gui.cpp create mode 100644 src/signs_type.h create mode 100644 src/slope_func.h create mode 100644 src/slope_type.h create mode 100644 src/smallmap_gui.cpp create mode 100644 src/smallmap_gui.h create mode 100644 src/sortlist_type.h create mode 100644 src/sound.cpp create mode 100644 src/sound/allegro_s.cpp create mode 100644 src/sound/allegro_s.h create mode 100644 src/sound/cocoa_s.cpp create mode 100644 src/sound/cocoa_s.h create mode 100644 src/sound/null_s.cpp create mode 100644 src/sound/null_s.h create mode 100644 src/sound/sdl_s.cpp create mode 100644 src/sound/sdl_s.h create mode 100644 src/sound/sound_driver.hpp create mode 100644 src/sound/win32_s.cpp create mode 100644 src/sound/win32_s.h create mode 100644 src/sound/xaudio2_s.cpp create mode 100644 src/sound/xaudio2_s.h create mode 100644 src/sound_func.h create mode 100644 src/sound_type.h create mode 100644 src/sprite.cpp create mode 100644 src/sprite.h create mode 100644 src/spritecache.cpp create mode 100644 src/spritecache.h create mode 100644 src/spriteloader/grf.cpp create mode 100644 src/spriteloader/grf.hpp create mode 100644 src/spriteloader/spriteloader.hpp create mode 100644 src/station.cpp create mode 100644 src/station_base.h create mode 100644 src/station_cmd.cpp create mode 100644 src/station_func.h create mode 100644 src/station_gui.cpp create mode 100644 src/station_gui.h create mode 100644 src/station_map.h create mode 100644 src/station_type.h create mode 100644 src/statusbar_gui.cpp create mode 100644 src/statusbar_gui.h create mode 100644 src/stdafx.h create mode 100644 src/story.cpp create mode 100644 src/story_base.h create mode 100644 src/story_gui.cpp create mode 100644 src/story_type.h create mode 100644 src/strgen/strgen.cpp create mode 100644 src/strgen/strgen.h create mode 100644 src/strgen/strgen_base.cpp create mode 100644 src/string.cpp create mode 100644 src/string_base.h create mode 100644 src/string_func.h create mode 100644 src/string_type.h create mode 100644 src/stringfilter.cpp create mode 100644 src/stringfilter_type.h create mode 100644 src/strings.cpp create mode 100644 src/strings_func.h create mode 100644 src/strings_type.h create mode 100644 src/subsidy.cpp create mode 100644 src/subsidy_base.h create mode 100644 src/subsidy_func.h create mode 100644 src/subsidy_gui.cpp create mode 100644 src/subsidy_type.h create mode 100644 src/table/airport_defaults.h create mode 100644 src/table/airport_movement.h create mode 100644 src/table/airporttile_ids.h create mode 100644 src/table/airporttiles.h create mode 100644 src/table/animcursors.h create mode 100644 src/table/autorail.h create mode 100644 src/table/bridge_land.h create mode 100644 src/table/build_industry.h create mode 100644 src/table/cargo_const.h create mode 100644 src/table/clear_land.h create mode 100644 src/table/company_settings.ini create mode 100644 src/table/control_codes.h create mode 100644 src/table/currency_settings.ini create mode 100644 src/table/elrail_data.h create mode 100644 src/table/engines.h create mode 100644 src/table/gameopt_settings.ini create mode 100644 src/table/genland.h create mode 100644 src/table/heightmap_colours.h create mode 100644 src/table/industry_land.h create mode 100644 src/table/landscape_sprite.h create mode 100644 src/table/misc_settings.ini create mode 100644 src/table/newgrf_debug_data.h create mode 100644 src/table/object_land.h create mode 100644 src/table/palette_convert.h create mode 100644 src/table/palettes.h create mode 100644 src/table/pricebase.h create mode 100644 src/table/railtypes.h create mode 100644 src/table/road_land.h create mode 100644 src/table/roadveh_movement.h create mode 100644 src/table/settings.h.postamble create mode 100644 src/table/settings.h.preamble create mode 100644 src/table/settings.ini create mode 100644 src/table/sprites.h create mode 100644 src/table/station_land.h create mode 100644 src/table/strgen_tables.h create mode 100644 src/table/string_colours.h create mode 100644 src/table/town_land.h create mode 100644 src/table/townname.h create mode 100644 src/table/track_land.h create mode 100644 src/table/train_cmd.h create mode 100644 src/table/tree_land.h create mode 100644 src/table/unicode.h create mode 100644 src/table/water_land.h create mode 100644 src/table/win32_settings.ini create mode 100644 src/table/window_settings.ini create mode 100644 src/tar_type.h create mode 100644 src/terraform_cmd.cpp create mode 100644 src/terraform_gui.cpp create mode 100644 src/terraform_gui.h create mode 100644 src/textbuf.cpp create mode 100644 src/textbuf_gui.h create mode 100644 src/textbuf_type.h create mode 100644 src/texteff.cpp create mode 100644 src/texteff.hpp create mode 100644 src/textfile_gui.cpp create mode 100644 src/textfile_gui.h create mode 100644 src/textfile_type.h create mode 100644 src/tgp.cpp create mode 100644 src/tgp.h create mode 100644 src/thread/thread.h create mode 100644 src/thread/thread_morphos.cpp create mode 100644 src/thread/thread_none.cpp create mode 100644 src/thread/thread_os2.cpp create mode 100644 src/thread/thread_pthread.cpp create mode 100644 src/thread/thread_win32.cpp create mode 100644 src/tile_cmd.h create mode 100644 src/tile_map.cpp create mode 100644 src/tile_map.h create mode 100644 src/tile_type.h create mode 100644 src/tilearea.cpp create mode 100644 src/tilearea_type.h create mode 100644 src/tilehighlight_func.h create mode 100644 src/tilehighlight_type.h create mode 100644 src/tilematrix_type.hpp create mode 100644 src/timetable.h create mode 100644 src/timetable_cmd.cpp create mode 100644 src/timetable_gui.cpp create mode 100644 src/toolbar_gui.cpp create mode 100644 src/toolbar_gui.h create mode 100644 src/town.h create mode 100644 src/town_cmd.cpp create mode 100644 src/town_gui.cpp create mode 100644 src/town_map.h create mode 100644 src/town_type.h create mode 100644 src/townname.cpp create mode 100644 src/townname_func.h create mode 100644 src/townname_type.h create mode 100644 src/track_func.h create mode 100644 src/track_type.h create mode 100644 src/train.h create mode 100644 src/train_cmd.cpp create mode 100644 src/train_gui.cpp create mode 100644 src/transparency.h create mode 100644 src/transparency_gui.cpp create mode 100644 src/transparency_gui.h create mode 100644 src/transport_type.h create mode 100644 src/tree_cmd.cpp create mode 100644 src/tree_gui.cpp create mode 100644 src/tree_map.h create mode 100644 src/tunnel_map.cpp create mode 100644 src/tunnel_map.h create mode 100644 src/tunnelbridge.h create mode 100644 src/tunnelbridge_cmd.cpp create mode 100644 src/tunnelbridge_map.h create mode 100644 src/vehicle.cpp create mode 100644 src/vehicle_base.h create mode 100644 src/vehicle_cmd.cpp create mode 100644 src/vehicle_func.h create mode 100644 src/vehicle_gui.cpp create mode 100644 src/vehicle_gui.h create mode 100644 src/vehicle_gui_base.h create mode 100644 src/vehicle_type.h create mode 100644 src/vehiclelist.cpp create mode 100644 src/vehiclelist.h create mode 100644 src/video/allegro_v.cpp create mode 100644 src/video/allegro_v.h create mode 100644 src/video/cocoa/cocoa_keys.h create mode 100644 src/video/cocoa/cocoa_v.h create mode 100644 src/video/cocoa/cocoa_v.mm create mode 100644 src/video/cocoa/event.mm create mode 100644 src/video/cocoa/fullscreen.mm create mode 100644 src/video/cocoa/wnd_quartz.mm create mode 100644 src/video/cocoa/wnd_quickdraw.mm create mode 100644 src/video/dedicated_v.cpp create mode 100644 src/video/dedicated_v.h create mode 100644 src/video/null_v.cpp create mode 100644 src/video/null_v.h create mode 100644 src/video/sdl_v.cpp create mode 100644 src/video/sdl_v.h create mode 100644 src/video/video_driver.hpp create mode 100644 src/video/win32_v.cpp create mode 100644 src/video/win32_v.h create mode 100644 src/viewport.cpp create mode 100644 src/viewport_func.h create mode 100644 src/viewport_gui.cpp create mode 100644 src/viewport_sprite_sorter.h create mode 100644 src/viewport_sprite_sorter_sse4.cpp create mode 100644 src/viewport_type.h create mode 100644 src/void_cmd.cpp create mode 100644 src/void_map.h create mode 100644 src/water.h create mode 100644 src/water_cmd.cpp create mode 100644 src/water_map.h create mode 100644 src/waypoint.cpp create mode 100644 src/waypoint_base.h create mode 100644 src/waypoint_cmd.cpp create mode 100644 src/waypoint_func.h create mode 100644 src/waypoint_gui.cpp create mode 100644 src/widget.cpp create mode 100644 src/widget_type.h create mode 100644 src/widgets/ai_widget.h create mode 100644 src/widgets/airport_widget.h create mode 100644 src/widgets/autoreplace_widget.h create mode 100644 src/widgets/bootstrap_widget.h create mode 100644 src/widgets/bridge_widget.h create mode 100644 src/widgets/build_vehicle_widget.h create mode 100644 src/widgets/cheat_widget.h create mode 100644 src/widgets/company_widget.h create mode 100644 src/widgets/console_widget.h create mode 100644 src/widgets/date_widget.h create mode 100644 src/widgets/depot_widget.h create mode 100644 src/widgets/dock_widget.h create mode 100644 src/widgets/dropdown.cpp create mode 100644 src/widgets/dropdown_func.h create mode 100644 src/widgets/dropdown_type.h create mode 100644 src/widgets/dropdown_widget.h create mode 100644 src/widgets/engine_widget.h create mode 100644 src/widgets/error_widget.h create mode 100644 src/widgets/fios_widget.h create mode 100644 src/widgets/framerate_widget.h create mode 100644 src/widgets/genworld_widget.h create mode 100644 src/widgets/goal_widget.h create mode 100644 src/widgets/graph_widget.h create mode 100644 src/widgets/group_widget.h create mode 100644 src/widgets/highscore_widget.h create mode 100644 src/widgets/industry_widget.h create mode 100644 src/widgets/intro_widget.h create mode 100644 src/widgets/link_graph_legend_widget.h create mode 100644 src/widgets/main_widget.h create mode 100644 src/widgets/misc_widget.h create mode 100644 src/widgets/music_widget.h create mode 100644 src/widgets/network_chat_widget.h create mode 100644 src/widgets/network_content_widget.h create mode 100644 src/widgets/network_widget.h create mode 100644 src/widgets/newgrf_debug_widget.h create mode 100644 src/widgets/newgrf_widget.h create mode 100644 src/widgets/news_widget.h create mode 100644 src/widgets/object_widget.h create mode 100644 src/widgets/order_widget.h create mode 100644 src/widgets/osk_widget.h create mode 100644 src/widgets/rail_widget.h create mode 100644 src/widgets/road_widget.h create mode 100644 src/widgets/settings_widget.h create mode 100644 src/widgets/sign_widget.h create mode 100644 src/widgets/smallmap_widget.h create mode 100644 src/widgets/station_widget.h create mode 100644 src/widgets/statusbar_widget.h create mode 100644 src/widgets/story_widget.h create mode 100644 src/widgets/subsidy_widget.h create mode 100644 src/widgets/terraform_widget.h create mode 100644 src/widgets/timetable_widget.h create mode 100644 src/widgets/toolbar_widget.h create mode 100644 src/widgets/town_widget.h create mode 100644 src/widgets/transparency_widget.h create mode 100644 src/widgets/tree_widget.h create mode 100644 src/widgets/vehicle_widget.h create mode 100644 src/widgets/viewport_widget.h create mode 100644 src/widgets/waypoint_widget.h create mode 100644 src/window.cpp create mode 100644 src/window_func.h create mode 100644 src/window_gui.h create mode 100644 src/window_type.h create mode 100644 src/zoom_func.h create mode 100644 src/zoom_type.h diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..2c7ce528c9 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,181 @@ + +# Contributing to OpenTTD + +Looking to contribute something to OpenTTD? **Here's how you can help.** + +Please take a moment to review this document in order to make the contribution process easy and effective for everyone involved. + +Following these guidelines helps to communicate that you respect the time of the developers managing and developing this open source project. In return, they should reciprocate that respect in addressing your issue or assessing patches and features. + + +## Using the issue tracker + +The [issue tracker](https://github.com/OpenTTD/OpenTTD/issues) is the preferred channel for [bug reports](#bug-reports), but please respect the following restrictions: + +* Please **do not** use the issue tracker for help playing or using OpenTTD. Please try [irc](https://wiki.openttd.org/IRC_channel), or the [forums](https://www.tt-forums.net/) + +* Please **do not** derail or troll issues. Keep the discussion on topic and respect the opinions of others. + +* Please **do not** post comments consisting solely of "+1" or ":thumbsup:". +Use [GitHub's "reactions" feature](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments) instead. We reserve the right to delete comments which violate this rule. + +* Please **do not** open issues or pull requests regarding add-on content in NewGRF, GameScripts, AIs, etc. These are created by third-parties. Please try [irc](https://wiki.openttd.org/IRC_channel) or the [forums](https://www.tt-forums.net/) to discuss these. + +## Bug reports + +A bug is a _demonstrable problem_ that is caused by the code in the repository. +Good bug reports are extremely helpful, so thanks! + +Guidelines for bug reports: + +0. Please don't report issues with games where you changed NewGRFs. + +1. Please don't report issues with modified versions of OpenTTD (patchpacks and similar). + +2. **Use the GitHub issue search** --- check if the issue has already been +reported. + +3. **Check if the issue has been fixed** --- try to reproduce it using the latest `nightly` build of OpenTTD, available from https://www.openttd.org + +4. **Isolate the problem** --- ideally create reproduceable steps with an attached savegame and screenshots. Try to use few or no NewGRFs, AIs etc if possible. + +A good bug report shouldn't leave others needing to chase you up for more information. +Please try to be as detailed as possible in your report. + +* What is your environment? +* What steps will reproduce the issue? +* Which operating system(s) experience the problem? +* What would you expect to be the outcome? + +All these details will help people to fix any potential bugs. + +Example: + +> Short and descriptive example bug report title +> +> A summary of the issue and the OS environment in which it occurs. If +> suitable, include the steps required to reproduce the bug. +> +> 1. This is the first step +> 2. This is the second step +> 3. Further steps, etc. +> +> Attached savegame +> Attached screenshots showing the issue +> Crashlogs if the bug causes a crash +> +> Any other information you want to share that is relevant to the issue being +> reported. This might include the lines of code that you have identified as +> causing the bug, and potential solutions (and your opinions on their +> merits). + +## Feature requests + +Before opening a feature request, please take a moment to find out whether your idea fits with the scope and aims of the project. + +It's up to *you* to make a strong case to convince the project's developers of the merits of this feature. + +Please provide as much detail and context as possible. This means don't request for a solution, but describe the problem you see and how/why you think it should be fixed. + +For feature request we have a strict policy. + +Keeping issues around with "a good idea" or "not really a bug but we should maybe fix it" turns out to have the reversed effect: nobody looks at it anymore. + +Although we really appreciate feedback and ideas, we will close feature requests that we don't expect to fulfill in the next year. + +Many of those ideas etc do have a place on the [forums](https://www.tt-forums.net); and if enough people like it, someone will stand up and make it. + +It's usually best discuss in [irc](https://wiki.openttd.org/IRC_channel) before opening a feature request or working on a large feature in a fork. +Discussion in irc can take time, but it can be productive and avoid disappointment :) + +## Pull requests + +Good pull requests—patches, improvements, new features—are a fantastic help. +They should remain focused in scope and avoid containing unrelated commits. + +**Please ask first** before embarking on any significant pull request (e.g. implementing features, refactoring code, porting to a different language), otherwise you risk spending a lot of time working on something that the project's developers might not want to merge into the project. + +Please adhere to the [coding guidelines](#code-guidelines) used throughout the project (indentation, accurate comments, etc.) and any other requirements (such as test coverage). + +Adhering to the following process is the best way to get your work included in the project: + +1. [Fork](https://help.github.com/fork-a-repo/) the project, clone your fork, and configure the remotes: + +```bash +git clone https://github.com//OpenTTD.git openttd +git clone https://github.com/OpenTTD/OpenTTD-git-hooks.git openttd_hooks +cd openttd +git remote add upstream https://github.com/OpenTTD/OpenTTD.git +cd .git/hooks +ln -s ../../../openttd_hooks/hooks/* . +``` + +2. If you cloned a while ago, get the latest changes from upstream: + +```bash +git fetch upstream +``` + +3. Create a new topic branch (off the main project development branch) to +contain your feature, change, or fix: + +```bash +git checkout upstream/master -b +``` + +4. Commit your changes in logical chunks. Please adhere to these [git commit message guidelines](https://wiki.openttd.org/Commit_style#Commit_message) or your code is unlikely to be merged into the main project. +Use Git's [interactive rebase](https://help.github.com/articles/interactive-rebase) feature to tidy up your commits before making them public. + +5. Locally rebase the upstream development branch into your topic branch: + +```bash +git fetch upstream +git rebase upstream/master +``` + +6. Push your topic branch up to your fork the first time: + +```bash +git push --set-upstream origin +``` + +And any time after that: + +```bash +git push +``` + +7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) with a clear title and description against the `master` branch. + +**IMPORTANT**: By submitting a patch, you agree to the [License](#license). + +### Privacy Notice + +We would like to make you aware that contributing to OpenTTD via git will permanently store the name and email address you provide as well as the actual changes and the time and date you made it inside git's version history. + +This is inevitable, because it is a main feature of git. If you are concerned about your privacy, we strongly recommend to use "Anonymous <anonymous@openttd.org>" as the git commit author. We might refuse anonymous contributions if malicious intent is suspected. + +Please note that the contributor identity, once given, is used for copyright verification and to provide proof should a malicious commit be made. As such, the [EU GDPR](https://www.eugdpr.org/key-changes.html) "right to be forgotten" does not apply, as this is an overriding legitimate interest. + +Please also note that your commit is public and as such will potentially be processed by many third-parties. Git's distributed nature makes it impossible to track where exactly your commit, and thus your personal data, will be stored and be processed. If you would not like to accept this risk, please do either commit anonymously or refrain from contributing to the OpenTTD project. + +### Pull request validation + +Continuous integration (CI) tools monitor pull requests, and help us identify build and code quality issues. + +The results of the CI tests will show on your pull request. + +By clicking on Details you can further zoom in; in case of a failure it will show you why it failed. In case of success it will report how awesome you were. + +## Code guidelines + +[Code style](https://wiki.openttd.org/Coding_style) must be adhered to for pull requests to be accepted + +## License + +By contributing your code, you agree to license your contribution under the [GPL v2](https://github.com/OpenTTD/OpenTTD/blob/master/COPYING). + +### Attribution of this Contributing Guide + +This contributing guide is adapted from [Bootstrap](https://github.com/twbs/bootstrap/blob/master/CONTRIBUTING.md) under the [Creative Commons Attribution 3.0 Unported License](https://github.com/twbs/bootstrap/blob/master/docs/LICENSE) terms for Bootstrap documentation. +The GDPR notice is adapted from [rsyslog](https://github.com/rsyslog/rsyslog/blob/master/CONTRIBUTING.md) under the [GNU General Public License](https://github.com/rsyslog/rsyslog/blob/master/COPYING). diff --git a/COPYING b/COPYING new file mode 100644 index 0000000000..b790734971 --- /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.md 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 0000000000..251b36be15 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,355 @@ +# $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 +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = OpenTTD +PROJECT_NUMBER = +PROJECT_BRIEF = +PROJECT_LOGO = +OUTPUT_DIRECTORY = docs/source/ +CREATE_SUBDIRS = YES +ALLOW_UNICODE_NAMES = 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 +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 2 +ALIASES = +TCL_SUBST = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +EXTENSION_MAPPING = +MARKDOWN_SUPPORT = YES +TOC_INCLUDE_HEADINGS = 0 +AUTOLINK_SUPPORT = YES +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +GROUP_NESTED_COMPOUNDS = NO +SUBGROUPING = YES +INLINE_GROUPED_CLASSES = NO +INLINE_SIMPLE_STRUCTS = NO +TYPEDEF_HIDES_STRUCT = NO +LOOKUP_CACHE_SIZE = 0 +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = YES +EXTRACT_PACKAGE = NO +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = YES +EXTRACT_ANON_NSPACES = 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 +HIDE_COMPOUND_REFERENCE= NO +SHOW_INCLUDE_FILES = YES +SHOW_GROUPED_MEMB_INC = NO +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +STRICT_PROTO_MATCHING = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = +CITE_BIB_FILES = +#--------------------------------------------------------------------------- +# 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_AS_ERROR = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = ./src/ +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.h \ + *.hpp +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = */3rdparty \ + */script/api +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = ./docs/ +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +FILTER_SOURCE_PATTERNS = +USE_MDFILE_AS_MAINPAGE = +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +REFERENCES_LINK_SOURCE = YES +SOURCE_TOOLTIPS = YES +USE_HTAGS = NO +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_EXTRA_STYLESHEET = +HTML_EXTRA_FILES = +HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +HTML_TIMESTAMP = NO +HTML_DYNAMIC_MENUS = YES +HTML_DYNAMIC_SECTIONS = NO +HTML_INDEX_NUM_ENTRIES = 100 +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_NAME = Publisher +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = YES +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project +DISABLE_INDEX = NO +GENERATE_TREEVIEW = YES +ENUM_VALUES_PER_LINE = 4 +TREEVIEW_WIDTH = 250 +EXT_LINKS_IN_WINDOW = NO +FORMULA_FONTSIZE = 10 +FORMULA_TRANSPARENT = YES +USE_MATHJAX = NO +MATHJAX_FORMAT = HTML-CSS +MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/ +MATHJAX_EXTENSIONS = +MATHJAX_CODEFILE = +SEARCHENGINE = NO +SERVER_BASED_SEARCH = NO +EXTERNAL_SEARCH = NO +SEARCHENGINE_URL = +SEARCHDATA_FILE = searchdata.xml +EXTERNAL_SEARCH_ID = +EXTRA_SEARCH_MAPPINGS = +#--------------------------------------------------------------------------- +# 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 = +LATEX_FOOTER = +LATEX_EXTRA_STYLESHEET = +LATEX_EXTRA_FILES = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +LATEX_SOURCE_CODE = NO +LATEX_BIB_STYLE = plain +LATEX_TIMESTAMP = 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 = +RTF_SOURCE_CODE = NO +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_SUBDIR = +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- +GENERATE_DOCBOOK = NO +DOCBOOK_OUTPUT = docbook +DOCBOOK_PROGRAMLISTING = NO +#--------------------------------------------------------------------------- +# 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_SORT \ + WITH_ICU_LAYOUT \ + UNICODE \ + _UNICODE \ + _GNU_SOURCE \ + FINAL= +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = objs/openttd.tag +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +EXTERNAL_PAGES = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +MSCGEN_PATH = +DIA_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +DOT_NUM_THREADS = 0 +DOT_FONTNAME = Helvetica +DOT_FONTSIZE = 10 +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +UML_LIMIT_NUM_FIELDS = 10 +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +INTERACTIVE_SVG = NO +DOT_PATH = +DOTFILE_DIRS = +MSCFILE_DIRS = +DIAFILE_DIRS = +PLANTUML_JAR_PATH = +PLANTUML_CFG_FILE = +PLANTUML_INCLUDE_PATH = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 1000 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES diff --git a/Makefile.bundle.in b/Makefile.bundle.in new file mode 100644 index 0000000000..eaf7134dde --- /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") +VERSION := $(shell echo "$(VERSIONS)" | cut -f 1 -d' ') + +# Make sure we have something in VERSION +ifeq ($(VERSION),) +VERSION := norev000 +endif + +ifndef BUNDLE_NAME +BUNDLE_NAME = openttd-custom-$(VERSION)-$(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)" "$(VERSION)" + $(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.md" "$(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 | LC_ALL=C $(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.md" "$(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 $(VERSION)" + $(Q)cp -R "$(BUNDLE_DIR)/" "$(BUNDLES_DIR)/OpenTTD $(VERSION)" + $(Q)hdiutil create -ov -format UDZO -srcfolder "$(BUNDLES_DIR)/OpenTTD $(VERSION)" "$(BUNDLES_DIR)/$(BUNDLE_NAME).dmg" + $(Q)rm -fr "$(BUNDLES_DIR)/OpenTTD $(VERSION)" + +bundle_exe: all + @echo '[BUNDLE] Creating $(BUNDLE_NAME).exe' + $(Q)mkdir -p "$(BUNDLES_DIR)" + $(Q)unix2dos "$(ROOT_DIR)/docs/"*.txt "$(ROOT_DIR)/README.md" "$(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.md" "$(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 0000000000..8e8113a033 --- /dev/null +++ b/Makefile.grf.in @@ -0,0 +1,118 @@ +# $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. +# +# Recent versions (including sources) can be found at: +# http://www.openttd.org/download-grfcodec +# +# The mercurial repository can be found at: +# http://hg.openttdcoop.org/grfcodec +# + + +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 + +# List of target files. +OBT_FILES := $(BIN_DIR)/orig_dos.obg +OBT_FILES += $(BIN_DIR)/orig_dos_de.obg +OBT_FILES += $(BIN_DIR)/orig_win.obg +OBT_FILES += $(BIN_DIR)/orig_dos.obs +OBT_FILES += $(BIN_DIR)/orig_win.obs +OBT_FILES += $(BIN_DIR)/no_sound.obs +OBT_FILES += $(BIN_DIR)/orig_dos.obm +OBT_FILES += $(BIN_DIR)/orig_win.obm +OBT_FILES += $(BIN_DIR)/no_music.obm +OBT_FILES += $(BIN_DIR)/orig_tto.obm + +# Build the GRF. +all: $(OBT_FILES) +ifdef GRFCODEC +all: $(BIN_DIR)/openttd.grf $(BIN_DIR)/orig_extra.grf +endif + +$(OBJS_DIR)/langfiles.tmp: $(LANG_DIR)/*.txt + $(E) '$(STAGE) Collecting baseset translations' + $(Q) cat $^ > $@ + +$(BIN_DIR)/%.obg: $(BASESET_DIR)/%.obg $(BIN_DIR)/orig_extra.grf $(OBJS_DIR)/langfiles.tmp $(BASESET_DIR)/translations.awk + $(E) '$(STAGE) Updating $(notdir $@)' + $(Q) sed 's/^ORIG_EXTRA.GRF = *[0-9a-f]*$$/ORIG_EXTRA.GRF = '`$(MD5SUM) $(BIN_DIR)/orig_extra.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 $< >$@ + +# Guard against trying to run GRFCODEC/NFORENUM without either being set. +ifdef GRFCODEC +ifdef NFORENUM + +# Compile extra grf +$(BIN_DIR)/openttd.grf: $(PNG_FILES) $(NFO_FILES) $(GRF_DIR)/assemble_nfo.awk + $(E) '$(STAGE) Assembling openttd.nfo' + $(Q)-mkdir -p $(OBJS_DIR)/sprites + $(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 + +# The copy operation of PNG_FILES is duplicated from the target 'openttd.grf', thus those targets may not run in parallel. +$(BIN_DIR)/orig_extra.grf: $(PNG_FILES) $(NFO_FILES) $(GRF_DIR)/assemble_nfo.awk | $(BIN_DIR)/openttd.grf + $(E) '$(STAGE) Assembling orig_extra.nfo' + $(Q)-mkdir -p $(OBJS_DIR)/sprites + $(Q)-cp $(PNG_FILES) $(OBJS_DIR)/sprites 2> /dev/null + $(Q) awk -f $(GRF_DIR)/assemble_nfo.awk $(GRF_DIR)/orig_extra.nfo > $(OBJS_DIR)/sprites/orig_extra.nfo + $(Q) $(NFORENUM) -s $(OBJS_DIR)/sprites/orig_extra.nfo + $(E) '$(STAGE) Compiling orig_extra.grf' + $(Q) $(GRFCODEC) -n -s -e -p1 $(OBJS_DIR)/orig_extra.grf + $(Q)cp $(OBJS_DIR)/orig_extra.grf $(BIN_DIR)/orig_extra.grf + +endif +endif + +# Clean up temporary files. +clean: + $(Q)rm -f *.bak *.grf $(OBT_FILES) + +# 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 0000000000..d33d8a0d2a --- /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/orig_extra.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 0000000000..2853ae3898 --- /dev/null +++ b/Makefile.lang.in @@ -0,0 +1,89 @@ +# $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!! +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 + +# 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 $(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 $(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 $(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 $(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 + +depend: + +clean: + $(E) '$(STAGE) Cleaning up language files' + $(Q)rm -f strgen_base.o strgen.o string.o alloc_func.o getoptdata.o table/strings.h $(STRGEN) $(LANGS) $(LANGS:%=$(BIN_DIR)/lang/%) lang/english.* + +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 0000000000..0a02c8cf95 --- /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 0000000000..1e2dc992f8 --- /dev/null +++ b/Makefile.setting.in @@ -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 . + +SETTINGSGEN = !!SETTINGSGEN!! +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!! + +# 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 $(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 $(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 + +depend: + +clean: + $(E) '$(STAGE) Cleaning up settings files' + $(Q)rm -f settingsgen.o alloc_func.o getoptdata.o string.o ini_load.o $(SETTINGSGEN) 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 0000000000..6b235be9d3 --- /dev/null +++ b/Makefile.src.in @@ -0,0 +1,300 @@ +# $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!! +DEPEND = !!DEPEND!! +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_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) +# Create all dirs and subdirs +RES := $(shell mkdir -p $(BIN_DIR) $(sort $(dir $(OBJS)))) + +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 + +# 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 +VERSION := $(shell echo "$(VERSIONS)" | cut -f 1 -d' ') +ISODATE := $(shell echo "$(VERSIONS)" | cut -f 2 -d' ') +GITHASH := $(shell echo "$(VERSIONS)" | cut -f 4 -d' ') +ISTAG := $(shell echo "$(VERSIONS)" | cut -f 5 -d' ') +ISSTABLETAG := $(shell echo "$(VERSIONS)" | cut -f 6 -d' ') + +# Make sure we have something in VERSION and ISODATE +ifeq ($(VERSION),) +VERSION := norev000 +endif +ifeq ($(ISODATE),) +ISODATE := 00000000 +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 ) + +# 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`" != "$(VERSION) $(MODIFIED)" ]; then echo "$(VERSION) $(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 %.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 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 + +# Macro for invoking a command on groups of 100 words at a time +# (analogous to xargs(1)). The macro invokes itself recursively +# until the list of words is depleted. +# +# Usage: $(call xargs,COMMAND,LIST) +# +# COMMAND should be a shell command to which the words will be +# appended as arguments in groups of 100. +define xargs +$(1) $(wordlist 1,100,$(2)) +$(if $(word 101,$(2)),$(call xargs,$(1),$(wordlist 101,$(words $(2)),$(2)))) +endef + +# 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 + $(call xargs,$(Q)$(MAKEDEPEND) -f$(SRC_OBJS_DIR)/Makefile.dep.tmp -o.o -Y -v -a -- $(CFLAGS_MAKEDEP) -- 2>/dev/null,$(SRCS:%=$(SRC_DIR)/%)) + +# 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@ $$@@' | LC_ALL=C $(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 $@ $< + +$(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 $@' + $(Q)+$(CXX_HOST) $(LDFLAGS) $(OBJS) $(LIBS) -o $@ +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 + +# Revision files + +$(SRC_DIR)/rev.cpp: $(CONFIG_CACHE_VERSION) $(SRC_DIR)/rev.cpp.in + $(Q)cat $(SRC_DIR)/rev.cpp.in | sed "s@\!\!ISODATE\!\!@$(ISODATE)@g;s@!!VERSION!!@$(VERSION)@g;s@!!MODIFIED!!@$(MODIFIED)@g;s@!!DATE!!@`date +%d.%m.%y`@g;s@!!GITHASH!!@$(GITHASH)@g;s@!!ISTAG!!@$(ISTAG)@g;s@!!ISSTABLETAG!!@$(ISSTABLETAG)@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@\!\!ISODATE\!\!@$(ISODATE)@g;s@!!VERSION!!@$(VERSION)@g;s@!!DATE!!@`date +%d.%m.%y`@g;s@!!GITHASH!!@$(GITHASH)@g;s@!!ISTAG!!@$(ISTAG)@g;s@!!ISSTABLETAG!!@$(ISSTABLETAG)@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_SOURCE) + +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/README.md b/README.md new file mode 100644 index 0000000000..e621dc0215 --- /dev/null +++ b/README.md @@ -0,0 +1,839 @@ +# OpenTTD + +## Table of contents + +- 1.0) [About](#10-about) +- 2.0) [Contacting](#20-contacting) + - 2.1) [Reporting bugs](#21-reporting-bugs) + - 2.2) [Reporting desyncs](#22-reporting-desyncs) +- 3.0) [Supported platforms](#30-supported-platforms) +- 4.0) [Installing and running OpenTTD](#40-installing-and-running-openttd) + - 4.1) [(Required) 3rd party files](#41-required-3rd-party-files) + - 4.2) [OpenTTD directories](#42-openttd-directories) + - 4.3) [Portable installations (portable media)](#43-portable-installations-portable-media) + - 4.4) [Files in tar (archives)](#44-files-in-tar-archives) +- 5.0) [OpenTTD features](#50-openttd-features) + - 5.1) [Logging of potentially dangerous actions](#51-logging-of-potentially-dangerous-actions) + - 5.2) [Frame rate and performance metrics](#52-frame-rate-and-performance-metrics) +- 6.0) [Configuration file](#60-configuration-file) +- 7.0) [Compiling](#70-compiling) + - 7.1) [Required/optional libraries](#71-requiredoptional-libraries) + - 7.2) [Supported compilers](#72-supported-compilers) + - 7.3) [Compilation of base sets](#73-compilation-of-base-sets) +- 8.0) [Translating](#80-translating) + - 8.1) [Translation](#81-translation) + - 8.2) [Previewing](#82-previewing) +- 9.0) [Troubleshooting](#90-troubleshooting) +- 10.0) [Licensing](#100-licensing) +- X.X) [Credits](#xx-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 https://www.openttd.org. + +You can also find the OpenTTD forums at +[https://www.tt-forums.net](https://www.tt-forums.net/viewforum.php?f=55). + +### 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 GitHub's issue tracker. You can find +the tracker at https://github.com/OpenTTD/OpenTTD/issues. 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 Git revision/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-bit Windows, 64-bit Windows, + Linux on an ARM, Mac OS X on a PowerPC, etc.) +- 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 (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: + +- https://www.openttd.org/download-opengfx for OpenGFX +- https://www.openttd.org/download-opensfx for OpenSFX +- https://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 appropriate files from +the original game into the baseset folder. +- TTD for Windows: All files in the gm/ folder (gm_tt00.gm up to gm_tt21.gm) +- TTD for DOS: The GM.CAT file +- Transport Tycoon Original: The GM.CAT file, but rename it to GM-TTO.CAT + +#### 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 https://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, 8.1, 10) + - macOS: `~/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, 8.1, 10) + - macOS: `/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 (macOS 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: + +| data type | directory | additional info | +| ------------------- | ----------------- | --------------------------- | +| 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/library | (or a subdirectory thereof) | +| Game Scripts (GS) | game | (or a subdirectory thereof) | +| GS Libraries | game/library | (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](https://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 https://wiki.openttd.org/Hidden_features + for a non-comprehensive list or look at the tooltips. +- Ingame console. More information at https://wiki.openttd.org/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. + +### 5.2) Frame rate and performance metrics + +The Help menu in-game has a function to open the Frame rate window. This +window shows various real-time performance statistics, measuring what parts +of the game require the most processing power currently. + +A summary of the statistics can also be retrieved from the console with the +`fps` command. This is especially useful on dedicated servers, where the +administrator might want to determine what's limiting performance in a slow +game. + +The frame rate is given as two figures, the simulation rate and the graphics +frame rate. Usually these are identical, as the screen is rendered exactly +once per simulated tick, but in the future there might be support for graphics +and simulation running at different rates. When the game is paused, the +simulation rate drops to zero. + +In addition to the simulation rate, a game speed factor is also calculated. +This is based on the target simulation speed, which is 30 milliseconds per +game tick. At that speed, the expected frame rate is 33.33 frames/second, and +the game speed factor is how close to that target the actual rate is. When +the game is in fast forward mode, the game speed factor shows how much +speed up is achieved. + +The lower part of the window shows timing statistics for individual parts of +the game. The times shown are short-term and long-term averages of how long +it takes to process one tick of game time, all figures are in milliseconds. + +Clicking a line in the lower part of the window opens a graph window, giving +detailed readings on each tick simulated by the game. + +The following is an explanation of the different statistics: + +- *Game loop* - Total processing time used per simulated "tick" in the game. + This includes all pathfinding, world updates, and economy handling. +- *Cargo handling* - Time spent loading/unloading cargo at stations, and + industries and towns sending/retrieving cargo from stations. +- *Train ticks*, *Road vehicle ticks*, *Ship ticks*, *Aircraft ticks* - + Time spent on pathfinding and other processing for each player vehicle type. +- *World ticks* - Time spent on other world/landscape processing. This + includes towns growing, building animations, updates of farmland and trees, + and station rating updates. +- *GS/AI total*, *Game script*, and *AI players* - Time spent running logic + for game scripts and AI players. The total may show as less than the current + sum of the individual scripts, this is because AI players at lower + difficulty settings do not run every game tick, and hence contribute less + to the average across all ticks. Keep in mind that the "Current" figure is + also an average, just only over short term. +- *Link graph delay* - Time overruns of the cargo distribution link graph + update thread. Usually the link graph is updated in a background thread, + but these updates need to synchronise with the main game loop occasionally, + if the time spent on link graph updates is longer than the time taken to + otherwise simulate the game while it was updating, these delays are counted + in this figure. +- *Graphics rendering* - Total time spent rendering all graphics, including + both GUI and world viewports. This typically spikes when panning the view + around, and when more things are happening on screen at once. +- *World viewport rendering* - Isolated time spent rendering just world + viewports. If this figure is significantly lower than the total graphics + rendering time, most time is spent rendering GUI than rendering world. +- *Video output* - Speed of copying the rendered graphics to the display + adapter. Usually this should be very fast (in the range of 0-3 ms), large + values for this can indicate a graphics driver problem. +- *Sound mixing* - Speed of mixing active audio samples together. Usually + this should be very fast (in the range of 0-3 ms), if it is slow, consider + switching to the NoSound set. + +If the frame rate window is shaded, the title bar will instead show just the +current simulation rate and the game speed factor. + +## 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 2015 Update 3 or more recent. 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), ZLIB (WITH_ZLIB), LZO (WITH_LZO), Freetype (WITH_FREETYPE) and +LZMA (WITH_LZMA) support is enabled by default. For these to work you need their +development files. To get them just use vcpkg from https://github.com/Microsoft/vcpkg +using x86-windows-static and x64-windows-static triplets. +For more help with VS see docs/Readme_Windows_MSVC.md. + +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: + +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 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) 2015, 2017 and 2019. +- 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) 2013 and earlier. + These old versions do not support modern C++ language features. +- 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 https://github.com/OpenTTD/OpenTTD/issues/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 https://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 https://www.openttd.org/development for up-to-date information. + +The use of the online Translator service, located at +https://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 (https://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 Git 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 https://wiki.openttd.org/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](https://www.tt-forums.net/viewforum.php?f=66) +or [GRFCrawler](https://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. + +CONTRIBUTING.md is adapted from +[Bootstrap](https://github.com/twbs/bootstrap/blob/master/CONTRIBUTING.md) +under the [Creative Commons Attribution 3.0 Unported +License](https://github.com/twbs/bootstrap/blob/master/docs/LICENSE) +terms for Bootstrap documentation. + +## X.X) Credits + +### The OpenTTD team (in alphabetical order): + +- Grzegorz Duczyński (adf88) - General coding (since 1.7.2) +- 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) +- Niels Martin Hansen (nielsm) - Music system, general coding (since 1.9) +- 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) - macOS 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) - macOS 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/azure-pipelines-ci.yml b/azure-pipelines-ci.yml new file mode 100644 index 0000000000..19c185894c --- /dev/null +++ b/azure-pipelines-ci.yml @@ -0,0 +1,73 @@ +trigger: +- master +- release/* +pr: +- master +- release/* + +jobs: +- job: windows + displayName: 'Windows' + pool: + vmImage: 'VS2017-Win2016' + + strategy: + matrix: + Win32: + BuildPlatform: 'Win32' + Win64: + BuildPlatform: 'x64' + + steps: + - template: azure-pipelines/templates/ci-git-rebase.yml + - template: azure-pipelines/templates/windows-dependencies.yml + - template: azure-pipelines/templates/ci-opengfx.yml + - template: azure-pipelines/templates/windows-build.yml + parameters: + BuildPlatform: $(BuildPlatform) + - script: | + call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x86 + cd projects + call regression.bat + displayName: 'Test' + +- job: linux + displayName: 'Linux' + pool: + vmImage: 'ubuntu-16.04' + + strategy: + matrix: + commit-checker: + Tag: 'commit-checker' + linux-amd64-clang-3.8: + Tag: 'linux-amd64-clang-3.8' + linux-amd64-gcc-6: + Tag: 'linux-amd64-gcc-6' + linux-i386-gcc-6: + Tag: 'linux-i386-gcc-6' + + steps: + - template: azure-pipelines/templates/ci-git-rebase.yml + # The dockers already have the dependencies installed + # The dockers already have OpenGFX installed + - template: azure-pipelines/templates/linux-build.yml + parameters: + Image: compile-farm-ci + Tag: $(Tag) + +- job: macos + displayName: 'MacOS' + pool: + vmImage: 'macOS-10.13' + + variables: + MACOSX_DEPLOYMENT_TARGET: 10.9 + + steps: + - template: azure-pipelines/templates/ci-git-rebase.yml + - template: azure-pipelines/templates/osx-dependencies.yml + - template: azure-pipelines/templates/ci-opengfx.yml + - template: azure-pipelines/templates/osx-build.yml + - script: 'make regression' + displayName: 'Test' diff --git a/azure-pipelines-release-stable.yml b/azure-pipelines-release-stable.yml new file mode 100644 index 0000000000..ee756ca9ee --- /dev/null +++ b/azure-pipelines-release-stable.yml @@ -0,0 +1,10 @@ +trigger: + branches: + include: + - refs/tags/* +pr: none + +jobs: +- template: azure-pipelines/templates/release.yml + parameters: + IsStableRelease: true diff --git a/azure-pipelines-release.yml b/azure-pipelines-release.yml new file mode 100644 index 0000000000..79e2da77ac --- /dev/null +++ b/azure-pipelines-release.yml @@ -0,0 +1,7 @@ +trigger: none +pr: none + +jobs: +- template: azure-pipelines/templates/release.yml + parameters: + IsStableRelease: false diff --git a/azure-pipelines/changelog.sh b/azure-pipelines/changelog.sh new file mode 100755 index 0000000000..33eb8a78d4 --- /dev/null +++ b/azure-pipelines/changelog.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +tag=$(git describe --tags 2>/dev/null) + +# If we are a tag, show the part of the changelog till (but excluding) the last stable +if [ -n "$tag" ]; then + grep='^[0-9]\.[0-9]\.[0-9][^-]' + next=$(cat changelog.txt | grep '^[0-9]' | awk 'BEGIN { show="false" } // { if (show=="true") print $0; if ($1=="'$tag'") show="true"} ' | grep "$grep" | head -n1 | sed 's/ .*//') + cat changelog.txt | awk 'BEGIN { show="false" } /^[0-9].[0-9].[0-9]/ { if ($1=="'$next'") show="false"; if ($1=="'$tag'") show="true";} // { if (show=="true") print $0 }' + exit 0 +fi + +# In all other cases, show the git log of the last 7 days +revdate=$(git log -1 --pretty=format:"%ci") +last_week=$(date -u -d "$revdate -7days" +"%Y-%m-%d %H:%M") +git log --after="${last_week}" --pretty=fuller diff --git a/azure-pipelines/manifest.sh b/azure-pipelines/manifest.sh new file mode 100755 index 0000000000..d8f4f9aac9 --- /dev/null +++ b/azure-pipelines/manifest.sh @@ -0,0 +1,60 @@ +#!/bin/sh + +set -ex + +if [ -z "$1" ]; then + echo "Usage: $0 " + exit 1 +fi + +FOLDER=$1 + +if [ ! -e .version ] || [ ! -e .release_date ]; then + echo "This script should be executed in the root of an extracted source tarball" + exit 1 +fi + +# Find the name based on the version +if [ -e .is_stable ]; then + isTesting=$(cat .version | grep "RC\|beta" || true) + if [ -z "${isTesting}" ]; then + NAME="stable" + else + NAME="testing" + fi +else + NAME=$(cat .version | cut -d- -f2 | cut -d- -f-2) +fi + +# Convert the date to a YAML date +DATE=$(cat .release_date | tr ' ' T | sed 's/TUTC/:00-00:00/') +VERSION=$(cat .version) +BASE="openttd-${VERSION}" + +echo "name: ${NAME}" >> manifest.yaml +echo "date: ${DATE}" >> manifest.yaml +echo "base: ${BASE}-" >> manifest.yaml +echo "files:" >> manifest.yaml + +error="" +for i in $(ls ${FOLDER} | grep -v ".txt$\|.md$\|sum$" | sort); do + if [ -n "$(echo $i | grep pdb.xz)" ]; then continue; fi + if [ -n "$(echo $i | grep dbg.deb)" ]; then continue; fi + + if [ ! -e ${FOLDER}/$i.md5sum ] || [ ! -e ${FOLDER}/$i.sha1sum ] || [ ! -e ${FOLDER}/$i.sha256sum ]; then + echo "ERROR: missing checksum file for ${i}" 1>&2 + error="y" + continue + fi + + echo "- id: $i" >> manifest.yaml + echo " size: $(stat -c"%s" ${FOLDER}/$i)" >> manifest.yaml + echo " md5sum: $(cat ${FOLDER}/$i.md5sum | cut -d\ -f1)" >> manifest.yaml + echo " sha1sum: $(cat ${FOLDER}/$i.sha1sum | cut -d\ -f1)" >> manifest.yaml + echo " sha256sum: $(cat ${FOLDER}/$i.sha256sum | cut -d\ -f1)" >> manifest.yaml +done + +if [ -n "${error}" ]; then + echo "ERROR: exiting due to earlier errors" 1>&2 + exit 1 +fi diff --git a/azure-pipelines/templates/ci-git-rebase.yml b/azure-pipelines/templates/ci-git-rebase.yml new file mode 100644 index 0000000000..96a23a5401 --- /dev/null +++ b/azure-pipelines/templates/ci-git-rebase.yml @@ -0,0 +1,10 @@ +steps: +# Rebase to target branch for every PR. This means users don't have to +# rebase every time target branch changes. As long as the PR applies cleanly, we +# will validate it. +- bash: | + git config user.email 'info@openttd.org' + git config user.name 'OpenTTD CI' + git rebase origin/${SYSTEM_PULLREQUEST_TARGETBRANCH} + displayName: 'Rebase to target branch' + condition: and(succeeded(), eq(variables['Build.Reason'], 'PullRequest')) diff --git a/azure-pipelines/templates/ci-opengfx.yml b/azure-pipelines/templates/ci-opengfx.yml new file mode 100644 index 0000000000..098f0d2a69 --- /dev/null +++ b/azure-pipelines/templates/ci-opengfx.yml @@ -0,0 +1,8 @@ +steps: +- bash: | + set -ex + cd bin/baseset + curl -L https://binaries.openttd.org/extra/opengfx/0.5.2/opengfx-0.5.2-all.zip > opengfx-0.5.2-all.zip + unzip opengfx-0.5.2-all.zip + rm -f opengfx-0.5.2-all.zip + displayName: 'Install OpenGFX' diff --git a/azure-pipelines/templates/linux-build.yml b/azure-pipelines/templates/linux-build.yml new file mode 100644 index 0000000000..a173f3364d --- /dev/null +++ b/azure-pipelines/templates/linux-build.yml @@ -0,0 +1,36 @@ +parameters: + Image: '' + Tag: '' + ContainerCommand: '' + +steps: +# 'envVars' in the 'Docker@1' task is a bit funky. When you want to use a +# variable, you have to quote it. But the quote is also sent directly to +# Docker and ends up in the variable, which you don't want. To work around +# this, we set the correct variable first (which becomes an env-variable), and +# pass that env-variable through to Docker. We cannot use the normal +# 'variables' entry, as we are a template. So that results in this bit of +# Bash code. Not because it is pretty, but it is the only way we found that +# works. +- bash: | + echo "##vso[task.setvariable variable=TARGET_BRANCH]${SYSTEM_PULLREQUEST_TARGETBRANCH}" + echo "Target branch is ${SYSTEM_PULLREQUEST_TARGETBRANCH}" + displayName: "Set target branch" + condition: and(succeeded(), eq(variables['Build.Reason'], 'PullRequest')) + +- task: Docker@1 + ${{ if eq(parameters.Image, 'compile-farm') }}: + displayName: 'Build' + ${{ if eq(parameters.Image, 'compile-farm-ci') }}: + displayName: 'Build and test' + # Run the commit-checker only if it is a Pull Request + condition: and(succeeded(), or(not(contains(variables['Agent.JobName'], 'commit-checker')), eq(variables['Build.Reason'], 'PullRequest'))) + inputs: + command: 'Run an image' + imageName: openttd/${{ parameters.Image }}:${{ parameters.Tag }} + volumes: '$(Build.SourcesDirectory):$(Build.SourcesDirectory)' + workingDirectory: '$(Build.SourcesDirectory)' + containerCommand: ${{ parameters.ContainerCommand }} + runInBackground: false + envVars: | + TARGET_BRANCH diff --git a/azure-pipelines/templates/linux-claim-bundles.yml b/azure-pipelines/templates/linux-claim-bundles.yml new file mode 100644 index 0000000000..4434dfcc7d --- /dev/null +++ b/azure-pipelines/templates/linux-claim-bundles.yml @@ -0,0 +1,5 @@ +steps: +# Because we run the compile in a docker (under root), we are not owner +# of the 'bundles' folder. Fix that by executing a chown on it. +- bash: sudo chown -R $(id -u):$(id -g) bundles + displayName: 'Claim bundles folder back' diff --git a/azure-pipelines/templates/osx-build.yml b/azure-pipelines/templates/osx-build.yml new file mode 100644 index 0000000000..ae1724125d --- /dev/null +++ b/azure-pipelines/templates/osx-build.yml @@ -0,0 +1,5 @@ +steps: +- script: './configure PKG_CONFIG_PATH=/usr/local/lib/pkgconfig --enable-static' + displayName: 'Configure' +- script: 'make -j2' + displayName: 'Build' diff --git a/azure-pipelines/templates/osx-dependencies.yml b/azure-pipelines/templates/osx-dependencies.yml new file mode 100644 index 0000000000..0393a56621 --- /dev/null +++ b/azure-pipelines/templates/osx-dependencies.yml @@ -0,0 +1,12 @@ +steps: +- script: | + set -ex + HOMEBREW_NO_AUTO_UPDATE=1 brew install pkg-config lzo xz libpng freetype + # Remove the dynamic libraries of these libraries, to ensure we use + # the static versions. That is important, as it is unlikely any + # end-user has these brew libraries installed. + rm /usr/local/Cellar/lzo/*/lib/*.dylib + rm /usr/local/Cellar/xz/*/lib/*.dylib + rm /usr/local/Cellar/libpng/*/lib/*.dylib + rm /usr/local/Cellar/freetype/*/lib/*.dylib + displayName: 'Install dependencies' diff --git a/azure-pipelines/templates/release-bundles.yml b/azure-pipelines/templates/release-bundles.yml new file mode 100644 index 0000000000..9c5a48b966 --- /dev/null +++ b/azure-pipelines/templates/release-bundles.yml @@ -0,0 +1,19 @@ +parameters: + CalculateChecksums: true + +steps: +- ${{ if eq(parameters.CalculateChecksums, true) }}: + - bash: | + set -ex + cd bundles + for i in $(ls); do + openssl dgst -r -md5 -hex $i > $i.md5sum + openssl dgst -r -sha1 -hex $i > $i.sha1sum + openssl dgst -r -sha256 -hex $i > $i.sha256sum + done + displayName: 'Calculate checksums' +- task: PublishBuildArtifacts@1 + displayName: 'Publish bundles' + inputs: + PathtoPublish: bundles/ + ArtifactName: bundles diff --git a/azure-pipelines/templates/release-fetch-source.yml b/azure-pipelines/templates/release-fetch-source.yml new file mode 100644 index 0000000000..8b43983067 --- /dev/null +++ b/azure-pipelines/templates/release-fetch-source.yml @@ -0,0 +1,20 @@ +# Fetch the source tarball as prepared by an earlier job. In there is the +# version predefined. This ensures we are all going to compile the same +# source with the same version. + +steps: +- checkout: none +- task: DownloadBuildArtifacts@0 + displayName: 'Download source' + inputs: + downloadType: specific + itemPattern: 'bundles/openttd-*-source.tar.xz' + downloadPath: '$(Build.ArtifactStagingDirectory)' +- bash: tar --xz -xf ../a/bundles/openttd-*-source.tar.xz --strip-components=1 + displayName: 'Extracting source' +- bash: | + set -e + VERSION=$(cat .version) + echo "${VERSION}" + echo "##vso[build.updatebuildnumber]${VERSION}" + displayName: 'Change BuildNumber to version' diff --git a/azure-pipelines/templates/release-manifest.yml b/azure-pipelines/templates/release-manifest.yml new file mode 100644 index 0000000000..9e8b486d5c --- /dev/null +++ b/azure-pipelines/templates/release-manifest.yml @@ -0,0 +1,20 @@ +parameters: + IsStableRelease: false + +steps: +- task: DownloadBuildArtifacts@0 + displayName: 'Download all bundles' + inputs: + downloadType: specific + itemPattern: 'bundles/*' + downloadPath: '$(Build.ArtifactStagingDirectory)' +- ${{ if eq(parameters.IsStableRelease, true) }}: + - script: | + touch .is_stable + displayName: 'Mark as stable release' +- script: | + set -ex + ./azure-pipelines/manifest.sh ../a/bundles/ + mkdir -p bundles + mv manifest.yaml bundles/ + displayName: 'Create manifest.yaml' diff --git a/azure-pipelines/templates/release-prepare-source.yml b/azure-pipelines/templates/release-prepare-source.yml new file mode 100644 index 0000000000..b20bf0b350 --- /dev/null +++ b/azure-pipelines/templates/release-prepare-source.yml @@ -0,0 +1,35 @@ +# Set the revisions, and remove the VCS files. +# This ensures everything else picks up on the predefined versions, and not +# that because of some build process the version all of a sudden changes. + +steps: +- script: | + set -ex + + if [ -n "${SYSTEM_PULLREQUEST_PULLREQUESTNUMBER}" ]; then + # We are triggered from a GitHub Pull Request + git checkout -B pr${SYSTEM_PULLREQUEST_PULLREQUESTNUMBER} + elif [ "${BUILD_SOURCEBRANCHNAME}" = "merge" ] || [ "${BUILD_SOURCEBRANCHNAME}" = "head" ]; then + # We are manually triggered based on a GitHub Pull Request + PULLREQUESTNUMBER=$(echo ${BUILD_SOURCEBRANCH} | cut -d/ -f3) + git checkout -B pr${PULLREQUESTNUMBER} + else + git checkout -B ${BUILD_SOURCEBRANCHNAME} + fi + + ./findversion.sh > .ottdrev + ./azure-pipelines/changelog.sh > .changelog + TZ='UTC' date +"%Y-%m-%d %H:%M UTC" > .release_date + cat .ottdrev | cut -f 1 -d$'\t' > .version + echo "Release Date: $(cat .release_date)" + echo "Revision: $(cat .ottdrev)" + echo "Version: $(cat .version)" + displayName: 'Create version files' +- script: | + set -e + VERSION=$(cat .version) + echo "${VERSION}" + echo "##vso[build.updatebuildnumber]${VERSION}" + displayName: 'Change BuildNumber to version' +- script: find . -iname .hg -or -iname .git -or -iname .svn | xargs rm -rf + displayName: 'Remove VCS information' diff --git a/azure-pipelines/templates/release.yml b/azure-pipelines/templates/release.yml new file mode 100644 index 0000000000..a1438c4a58 --- /dev/null +++ b/azure-pipelines/templates/release.yml @@ -0,0 +1,183 @@ +parameters: + # If this is false, not all targets are triggered. For example: + # The NSIS installer for Windows and the creation of debs only work for + # releases. Not for any other type of binary. So they are skilled if this + # is set to false. + IsStableRelease: false + +jobs: +- job: source + displayName: 'Source' + pool: + vmImage: 'ubuntu-16.04' + + steps: + - template: release-prepare-source.yml + - script: | + set -ex + + # Rename the folder to openttd-NNN-source + mkdir openttd-$(Build.BuildNumber) + find . -maxdepth 1 -not -name . -not -name openttd-$(Build.BuildNumber) -exec mv {} openttd-$(Build.BuildNumber)/ \; + # Copy back release_date, as it is needed for the template 'release-bundles' + cp openttd-$(Build.BuildNumber)/.release_date .release_date + + mkdir bundles + tar --xz -cf bundles/openttd-$(Build.BuildNumber)-source.tar.xz openttd-$(Build.BuildNumber) + zip -9 -r -q bundles/openttd-$(Build.BuildNumber)-source.zip openttd-$(Build.BuildNumber) + displayName: 'Create bundle' + - template: release-bundles.yml + +- job: meta + displayName: 'Metadata' + pool: + vmImage: 'ubuntu-16.04' + dependsOn: source + + steps: + - template: release-fetch-source.yml + - script: | + set -ex + + mkdir -p bundles + cp .changelog bundles/changelog.txt + cp .release_date bundles/released.txt + cp README.md bundles/README.md + displayName: 'Copy meta files' + - template: release-bundles.yml + parameters: + CalculateChecksums: false + +- job: docs + displayName: 'Docs' + pool: + vmImage: 'ubuntu-16.04' + dependsOn: source + + steps: + - template: release-fetch-source.yml + - template: linux-build.yml + parameters: + Image: compile-farm + ContainerCommand: '$(Build.BuildNumber)' + Tag: docs + - template: linux-claim-bundles.yml + - template: release-bundles.yml + +- job: windows + displayName: 'Windows' + pool: + vmImage: 'VS2017-Win2016' + dependsOn: source + + strategy: + matrix: + Win32: + BuildPlatform: 'Win32' + BundlePlatform: 'win32' + Win64: + BuildPlatform: 'x64' + BundlePlatform: 'win64' + + steps: + - template: release-fetch-source.yml + - template: windows-dependencies.yml + - template: windows-dependency-zip.yml + - ${{ if eq(parameters.IsStableRelease, true) }}: + - template: windows-dependency-nsis.yml + - template: windows-build.yml + parameters: + BuildPlatform: $(BuildPlatform) + - bash: | + set -ex + make -f Makefile.msvc bundle_pdb bundle_zip PLATFORM=$(BundlePlatform) BUNDLE_NAME=openttd-$(Build.BuildNumber)-windows-$(BundlePlatform) + displayName: 'Create bundles' + - ${{ if eq(parameters.IsStableRelease, true) }}: + - bash: | + set -ex + # NSIS will be part of the Hosted image in the next update. Till then, we set the PATH ourself + export PATH="${PATH}:/c/Program Files (x86)/NSIS" + make -f Makefile.msvc bundle_exe PLATFORM=$(BundlePlatform) BUNDLE_NAME=openttd-$(Build.BuildNumber)-windows-$(BundlePlatform) + displayName: 'Create installer bundle' + - template: release-bundles.yml + +- ${{ if eq(parameters.IsStableRelease, true) }}: + - job: linux_stable + displayName: 'Linux' + pool: + vmImage: 'ubuntu-16.04' + dependsOn: source + + strategy: + matrix: + linux-ubuntu-xenial-i386-gcc: + Tag: 'linux-ubuntu-xenial-i386-gcc' + linux-ubuntu-xenial-amd64-gcc: + Tag: 'linux-ubuntu-xenial-amd64-gcc' + linux-ubuntu-bionic-i386-gcc: + Tag: 'linux-ubuntu-bionic-i386-gcc' + linux-ubuntu-bionic-amd64-gcc: + Tag: 'linux-ubuntu-bionic-amd64-gcc' + linux-debian-jessie-i386-gcc: + Tag: 'linux-debian-jessie-i386-gcc' + linux-debian-jessie-amd64-gcc: + Tag: 'linux-debian-jessie-amd64-gcc' + linux-debian-stretch-i386-gcc: + Tag: 'linux-debian-stretch-i386-gcc' + linux-debian-stretch-amd64-gcc: + Tag: 'linux-debian-stretch-amd64-gcc' + + steps: + - template: release-fetch-source.yml + - template: linux-build.yml + parameters: + Image: compile-farm + ContainerCommand: '$(Build.BuildNumber)' + Tag: $(Tag) + - template: linux-claim-bundles.yml + - template: release-bundles.yml + +- job: macos + displayName: 'MacOS' + pool: + vmImage: 'macOS-10.13' + dependsOn: source + + variables: + MACOSX_DEPLOYMENT_TARGET: 10.9 + + steps: + - template: release-fetch-source.yml + - template: osx-dependencies.yml + - template: osx-build.yml + - script: 'make bundle_zip bundle_dmg BUNDLE_NAME=openttd-$(Build.BuildNumber)-macosx' + displayName: 'Create bundles' + - template: release-bundles.yml + +- job: manifest + displayName: 'Manifest' + pool: + vmImage: 'ubuntu-16.04' + dependsOn: + - source + - docs + - windows + - ${{ if eq(parameters.IsStableRelease, true) }}: + - linux_stable + - macos + # "Skipped" is not a status, and is not succeeded. So it seems to be + # considered failed. So we trigger if all the earlier jobs are done (which + # might be succeeded, failed, or skipped), and run this job. This is not + # optimal, but given the rules, it is the only way to get this to work (as + # some jobs might be skipped). + condition: succeededOrFailed() + + steps: + - template: release-fetch-source.yml + - template: release-manifest.yml + ${{ if eq(parameters.IsStableRelease, true) }}: + parameters: + IsStableRelease: true + - template: release-bundles.yml + parameters: + CalculateChecksums: false diff --git a/azure-pipelines/templates/windows-build.yml b/azure-pipelines/templates/windows-build.yml new file mode 100644 index 0000000000..5e12f2243f --- /dev/null +++ b/azure-pipelines/templates/windows-build.yml @@ -0,0 +1,11 @@ +parameters: + BuildPlatform: '' + +steps: +- task: VSBuild@1 + displayName: 'Build' + inputs: + solution: 'projects/openttd_vs141.sln' + platform: ${{ parameters.BuildPlatform }} + configuration: Release + maximumCpuCount: true diff --git a/azure-pipelines/templates/windows-dependencies.yml b/azure-pipelines/templates/windows-dependencies.yml new file mode 100644 index 0000000000..72368b9d71 --- /dev/null +++ b/azure-pipelines/templates/windows-dependencies.yml @@ -0,0 +1,14 @@ +steps: +- bash: | + set -ex + + curl -L https://github.com/OpenTTD/CompileFarm/releases/download/latest/windows-dependencies.zip > windows-dependencies.zip + unzip windows-dependencies.zip + rm -f windows-dependencies.zip + + mv windows-dependencies/installed /c/vcpkg/ + rm -rf windows-dependencies + displayName: 'Install dependencies' + workingDirectory: $(Build.ArtifactStagingDirectory) +- script: c:\vcpkg\vcpkg.exe integrate install + displayName: 'Integrate vcpkg' diff --git a/azure-pipelines/templates/windows-dependency-nsis.yml b/azure-pipelines/templates/windows-dependency-nsis.yml new file mode 100644 index 0000000000..9b54a3ac5f --- /dev/null +++ b/azure-pipelines/templates/windows-dependency-nsis.yml @@ -0,0 +1,26 @@ +parameters: + condition: true + +steps: +- bash: | + set -ex + + mkdir nsis-plugin; cd nsis-plugin + curl -L https://devs.openttd.org/~truebrain/nsis-plugins/Nsis7z.zip > Nsis7z.zip + unzip Nsis7z.zip + cp -R Plugins/* "/c/Program Files (x86)/NSIS/Plugins/" + cd ..; rm -rf nsis-plugin + + mkdir nsis-plugin; cd nsis-plugin + curl -L https://devs.openttd.org/~truebrain/nsis-plugins/NsisGetVersion.zip > NsisGetVersion.zip + unzip NsisGetVersion.zip + cp -R Plugins/* "/c/Program Files (x86)/NSIS/Plugins/x86-ansi/" + cd ..; rm -rf nsis-plugin + + mkdir nsis-plugin; cd nsis-plugin + curl -L https://devs.openttd.org/~truebrain/nsis-plugins/NsisFindProc.zip > NsisFindProc.zip + unzip NsisFindProc.zip + cp -R *.dll "/c/Program Files (x86)/NSIS/Plugins/x86-ansi/" + cd ..; rm -rf nsis-plugin + displayName: 'Install NSIS with the 7z, GetVersion, and FindProc plugins' + condition: and(succeeded(), ${{ parameters.condition }}) diff --git a/azure-pipelines/templates/windows-dependency-zip.yml b/azure-pipelines/templates/windows-dependency-zip.yml new file mode 100644 index 0000000000..e2ae06dbe7 --- /dev/null +++ b/azure-pipelines/templates/windows-dependency-zip.yml @@ -0,0 +1,5 @@ +steps: +- bash: | + set -ex + choco install zip + displayName: 'Install zip' diff --git a/bin/ai/compat_0.7.nut b/bin/ai/compat_0.7.nut new file mode 100644 index 0000000000..86ab06bba5 --- /dev/null +++ b/bin/ai/compat_0.7.nut @@ -0,0 +1,383 @@ +/* $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 + +/* 1.9 adds a vehicle type parameter. */ +AIBridge._GetName <- AIBridge.GetName; +AIBridge.GetName <- function(bridge_id) +{ + return AIBridge._GetName(bridge_id, AIVehicle.VT_RAIL); +} + +/* 1.9 adds parent_group_id to CreateGroup function */ +AIGroup._CreateGroup <- AIGroup.CreateGroup; +AIGroup.CreateGroup <- function(vehicle_type) +{ + return AIGroup._CreateGroup(vehicle_type, AIGroup.GROUP_INVALID); +} diff --git a/bin/ai/compat_1.0.nut b/bin/ai/compat_1.0.nut new file mode 100644 index 0000000000..6aa0e1a973 --- /dev/null +++ b/bin/ai/compat_1.0.nut @@ -0,0 +1,135 @@ +/* $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 + +/* 1.9 adds a vehicle type parameter. */ +AIBridge._GetName <- AIBridge.GetName; +AIBridge.GetName <- function(bridge_id) +{ + return AIBridge._GetName(bridge_id, AIVehicle.VT_RAIL); +} + +/* 1.9 adds parent_group_id to CreateGroup function */ +AIGroup._CreateGroup <- AIGroup.CreateGroup; +AIGroup.CreateGroup <- function(vehicle_type) +{ + return AIGroup._CreateGroup(vehicle_type, AIGroup.GROUP_INVALID); +} diff --git a/bin/ai/compat_1.1.nut b/bin/ai/compat_1.1.nut new file mode 100644 index 0000000000..3d7b7553ee --- /dev/null +++ b/bin/ai/compat_1.1.nut @@ -0,0 +1,72 @@ +/* $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 + +/* 1.9 adds a vehicle type parameter. */ +AIBridge._GetName <- AIBridge.GetName; +AIBridge.GetName <- function(bridge_id) +{ + return AIBridge._GetName(bridge_id, AIVehicle.VT_RAIL); +} + +/* 1.9 adds parent_group_id to CreateGroup function */ +AIGroup._CreateGroup <- AIGroup.CreateGroup; +AIGroup.CreateGroup <- function(vehicle_type) +{ + return AIGroup._CreateGroup(vehicle_type, AIGroup.GROUP_INVALID); +} diff --git a/bin/ai/compat_1.2.nut b/bin/ai/compat_1.2.nut new file mode 100644 index 0000000000..594ba98352 --- /dev/null +++ b/bin/ai/compat_1.2.nut @@ -0,0 +1,24 @@ +/* $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."); + +/* 1.9 adds a vehicle type parameter. */ +AIBridge._GetName <- AIBridge.GetName; +AIBridge.GetName <- function(bridge_id) +{ + return AIBridge._GetName(bridge_id, AIVehicle.VT_RAIL); +} + +/* 1.9 adds parent_group_id to CreateGroup function */ +AIGroup._CreateGroup <- AIGroup.CreateGroup; +AIGroup.CreateGroup <- function(vehicle_type) +{ + return AIGroup._CreateGroup(vehicle_type, AIGroup.GROUP_INVALID); +} diff --git a/bin/ai/compat_1.3.nut b/bin/ai/compat_1.3.nut new file mode 100644 index 0000000000..fb0f41d308 --- /dev/null +++ b/bin/ai/compat_1.3.nut @@ -0,0 +1,24 @@ +/* $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."); + +/* 1.9 adds a vehicle type parameter. */ +AIBridge._GetName <- AIBridge.GetName; +AIBridge.GetName <- function(bridge_id) +{ + return AIBridge._GetName(bridge_id, AIVehicle.VT_RAIL); +} + +/* 1.9 adds parent_group_id to CreateGroup function */ +AIGroup._CreateGroup <- AIGroup.CreateGroup; +AIGroup.CreateGroup <- function(vehicle_type) +{ + return AIGroup._CreateGroup(vehicle_type, AIGroup.GROUP_INVALID); +} diff --git a/bin/ai/compat_1.4.nut b/bin/ai/compat_1.4.nut new file mode 100644 index 0000000000..4bbb971604 --- /dev/null +++ b/bin/ai/compat_1.4.nut @@ -0,0 +1,24 @@ +/* $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."); + +/* 1.9 adds a vehicle type parameter. */ +AIBridge._GetName <- AIBridge.GetName; +AIBridge.GetName <- function(bridge_id) +{ + return AIBridge._GetName(bridge_id, AIVehicle.VT_RAIL); +} + +/* 1.9 adds parent_group_id to CreateGroup function */ +AIGroup._CreateGroup <- AIGroup.CreateGroup; +AIGroup.CreateGroup <- function(vehicle_type) +{ + return AIGroup._CreateGroup(vehicle_type, AIGroup.GROUP_INVALID); +} diff --git a/bin/ai/compat_1.5.nut b/bin/ai/compat_1.5.nut new file mode 100644 index 0000000000..b006f1733e --- /dev/null +++ b/bin/ai/compat_1.5.nut @@ -0,0 +1,24 @@ +/* $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.5 API compatibility in effect."); + +/* 1.9 adds a vehicle type parameter. */ +AIBridge._GetName <- AIBridge.GetName; +AIBridge.GetName <- function(bridge_id) +{ + return AIBridge._GetName(bridge_id, AIVehicle.VT_RAIL); +} + +/* 1.9 adds parent_group_id to CreateGroup function */ +AIGroup._CreateGroup <- AIGroup.CreateGroup; +AIGroup.CreateGroup <- function(vehicle_type) +{ + return AIGroup._CreateGroup(vehicle_type, AIGroup.GROUP_INVALID); +} diff --git a/bin/ai/compat_1.6.nut b/bin/ai/compat_1.6.nut new file mode 100644 index 0000000000..e57a3cb980 --- /dev/null +++ b/bin/ai/compat_1.6.nut @@ -0,0 +1,24 @@ +/* $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.6 API compatibility in effect."); + +/* 1.9 adds a vehicle type parameter. */ +AIBridge._GetName <- AIBridge.GetName; +AIBridge.GetName <- function(bridge_id) +{ + return AIBridge._GetName(bridge_id, AIVehicle.VT_RAIL); +} + +/* 1.9 adds parent_group_id to CreateGroup function */ +AIGroup._CreateGroup <- AIGroup.CreateGroup; +AIGroup.CreateGroup <- function(vehicle_type) +{ + return AIGroup._CreateGroup(vehicle_type, AIGroup.GROUP_INVALID); +} diff --git a/bin/ai/compat_1.7.nut b/bin/ai/compat_1.7.nut new file mode 100644 index 0000000000..ae403d104b --- /dev/null +++ b/bin/ai/compat_1.7.nut @@ -0,0 +1,24 @@ +/* $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.7 API compatibility in effect."); + +/* 1.9 adds a vehicle type parameter. */ +AIBridge._GetName <- AIBridge.GetName; +AIBridge.GetName <- function(bridge_id) +{ + return AIBridge._GetName(bridge_id, AIVehicle.VT_RAIL); +} + +/* 1.9 adds parent_group_id to CreateGroup function */ +AIGroup._CreateGroup <- AIGroup.CreateGroup; +AIGroup.CreateGroup <- function(vehicle_type) +{ + return AIGroup._CreateGroup(vehicle_type, AIGroup.GROUP_INVALID); +} diff --git a/bin/ai/compat_1.8.nut b/bin/ai/compat_1.8.nut new file mode 100644 index 0000000000..ecf4accdde --- /dev/null +++ b/bin/ai/compat_1.8.nut @@ -0,0 +1,24 @@ +/* $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.8 API compatibility in effect."); + +/* 1.9 adds a vehicle type parameter. */ +AIBridge._GetName <- AIBridge.GetName; +AIBridge.GetName <- function(bridge_id) +{ + return AIBridge._GetName(bridge_id, AIVehicle.VT_RAIL); +} + +/* 1.9 adds parent_group_id to CreateGroup function */ +AIGroup._CreateGroup <- AIGroup.CreateGroup; +AIGroup.CreateGroup <- function(vehicle_type) +{ + return AIGroup._CreateGroup(vehicle_type, AIGroup.GROUP_INVALID); +} diff --git a/bin/ai/compat_1.9.nut b/bin/ai/compat_1.9.nut new file mode 100644 index 0000000000..fe985b90d0 --- /dev/null +++ b/bin/ai/compat_1.9.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 0000000000..9f5e96eb0b --- /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 0000000000000000000000000000000000000000..cf97052c2e174d8203e2e190d3f98a2b067d7f3c GIT binary patch literal 97731 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%0D1=*@2G|9yDFKk7 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 I$J>4Z0A$aBVE_OC literal 0 HcmV?d00001 diff --git a/bin/ai/regression/regression.cfg b/bin/ai/regression/regression.cfg new file mode 100644 index 0000000000..4b8a5f6cd0 --- /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 0000000000..341d13a085 --- /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.9"; } + 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 0000000000..c9197c4d56 --- /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: \[.*\]' > $tst/tmp.regression + fi + + if [ -z "$gdb" ]; then + res="`diff -ub $tst/result.txt $tst/tmp.regression`" + if [ -z "$res" ]; then + echo "passed!" + else + echo "failed! Difference:" + echo "$res" + ret=1 + fi + fi + + rm $tst/info.nut + + if [ "$1" != "-k" ]; then + rm -f $tst/tmp.regression + fi +done + +if [ -f scripts/game_start.scr.regression ]; then + mv scripts/game_start.scr.regression scripts/game_start.scr +fi + +exit $ret diff --git a/bin/ai/regression/run.vbs b/bin/ai/regression/run.vbs new file mode 100644 index 0000000000..930562ec68 --- /dev/null +++ b/bin/ai/regression/run.vbs @@ -0,0 +1,154 @@ +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") + +Function GetTestList() + Dim retests, i, tests, dir + Set retests = New RegExp + Set GetTestList = CreateObject("Scripting.Dictionary") + + retests.Pattern = "ai/regression/tst_*" + retests.Global = True + For i = 0 To WScript.Arguments.Count - 1 + Dim test + test = "ai/regression/tst_" & WScript.Arguments.Item(i) + If FSO.FolderExists(test) Then + retests.Pattern = test + Exit For + End If + Next + + For Each dir In FSO.GetFolder("ai/regression/").SubFolders + Dim name + name = "ai/regression/" & dir.Name + If retests.Test(name) Then + GetTestList.Add name, name + End If + Next +End Function + +Function GetParams() + GetParams = "-snull -mnull -vnull:ticks=30000" + If WScript.Arguments.Count = 0 Then Exit Function + If WScript.Arguments.Item(0) <> "-r" Then Exit Function + GetParams = "" +End Function + +Sub FilterFile(filename) + Dim lines, filter, file + + Set file = FSO.OpenTextFile(filename, 1) + If Not file.AtEndOfStream Then + lines = file.ReadAll + End If + file.Close + + Set filter = New RegExp + filter.Global = True + filter.Multiline = True + filter.Pattern = "0x(\(nil\)|0+)(x0)?" + lines = filter.Replace(lines, "0x00000000") + filter.Pattern = "^dbg: \[script\]" + lines = filter.Replace(lines, "") + filter.Pattern = "^ " + lines = filter.Replace(lines, "ERROR: ") + filter.Pattern = "ERROR: \[1\] \[P\] " + lines = filter.Replace(lines, "") + filter.Pattern = "^dbg: .*\r\n" + lines = filter.Replace(lines, "") + + Set file = FSO.OpenTextFile(filename, 2) + file.Write lines + file.Close +End Sub + +Function CompareFiles(filename1, filename2) + Dim file, lines1, lines2 + Set file = FSO.OpenTextFile(filename1, 1) + If Not file.AtEndOfStream Then + lines1 = file.ReadAll + End IF + file.Close + Set file = FSO.OpenTextFile(filename2, 1) + If Not file.AtEndOfStream Then + lines2 = file.ReadAll + End IF + file.Close + CompareFiles = (lines1 = lines2) +End Function + +Function RunTest(test, params, ret) + Dim WshShell, oExec, sav, command + Set WshShell = CreateObject("WScript.Shell") + + ' Make sure that only one info.nut is present for each test run. Otherwise openttd gets confused. + FSO.CopyFile "ai/regression/regression_info.nut", test & "/info.nut" + + sav = test & "/test.sav" + If Not FSO.FileExists(sav) Then + sav = "ai/regression/empty.sav" + End If + + command = ".\openttd -x -c ai/regression/regression.cfg " & params & " -g " & sav & " -d script=2 -d misc=9" + ' 2>&1 must be after >tmp.regression, else stderr is not redirected to the file + WshShell.Run "cmd /c " & command & " >"& test & "/tmp.regression 2>&1", 0, True + + FilterFile test & "/tmp.regression" + + If CompareFiles(test & "/result.txt", test & "/tmp.regression") Then + RunTest = "passed!" + Else + RunTest = "failed!" + ret = 1 + End If + + FSO.DeleteFile test & "/info.nut" + + If WScript.Arguments.Count > 0 Then + If WScript.Arguments.Item(0) = "-k" Then + Exit Function + End If + End If + + FSO.DeleteFile test & "/tmp.regression" +End Function + +On Error Resume Next +WScript.StdOut.WriteLine "" +If Err.Number <> 0 Then + WScript.Echo "This script must be started with cscript." + WScript.Quit 1 +End If +On Error Goto 0 + +If Not FSO.FileExists("ai/regression/run.vbs") Then + WScript.Echo "Make sure you are in the root of OpenTTD before starting this script." + WScript.Quit 1 +End If + +If FSO.FileExists("scripts/game_start.scr") Then + FSO.MoveFile "scripts/game_start.scr", "scripts/game_start.scr.regression" +End If + +Dim params, test, ret +params = GetParams() +ret = 0 + +For Each test in GetTestList() + WScript.StdOut.Write "Running " & test & "... " + WScript.StdOut.WriteLine RunTest(test, params, ret) +Next + +If FSO.FileExists("scripts/game_start.scr.regression") Then + FSO.MoveFile "scripts/game_start.scr.regression", "scripts/game_start.scr" +End If + +WScript.Quit ret diff --git a/bin/ai/regression/tst_regression/main.nut b/bin/ai/regression/tst_regression/main.nut new file mode 100644 index 0000000000..7315f33f82 --- /dev/null +++ b/bin/ai/regression/tst_regression/main.nut @@ -0,0 +1,1921 @@ +/* $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():"); + print(" VT_RAIL: " + AIBridge.GetName(i, AIVehicle.VT_RAIL)); + print(" VT_ROAD: " + AIBridge.GetName(i, AIVehicle.VT_ROAD)); + print(" VT_WATER: " + AIBridge.GetName(i, AIVehicle.VT_WATER)); + print(" VT_AIR: " + AIBridge.GetName(i, AIVehicle.VT_AIR)); + 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, AIGroup.GROUP_INVALID); + 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(10006, 10005, 10002)); + print(" HasTransportType(): " + AITile.HasTransportType(10004, AITile.TRANSPORT_RAIL)); + print(" HasTransportType(): " + AITile.HasTransportType(10005, AITile.TRANSPORT_RAIL)); + print(" BuildRailTrack(): " + AIRail.BuildRailTrack(6200, AIRail.RAILTRACK_NE_SW)); + print(" RemoveRailTrack(): " + AIRail.RemoveRailTrack(6200, AIRail.RAILTRACK_NW_NE)); + print(" RemoveRailTrack(): " + AIRail.RemoveRailTrack(6200, AIRail.RAILTRACK_NE_SW)); + print(" BuildRail(): " + AIRail.BuildRail(6200, 6200 + 256, 6200 + (256 * 4))); + print(" HasTransportType(): " + AITile.HasTransportType(6200 + (256 * 3), AITile.TRANSPORT_RAIL)); + print(" HasTransportType(): " + AITile.HasTransportType(6200 + (256 * 4), AITile.TRANSPORT_RAIL)); + print(" RemoveRail(): " + AIRail.RemoveRail(6200 + (256 * 3), 6200 + (256 * 2), 6200 - 256)); + print(" HasTransportType(): " + AITile.HasTransportType(6200 + (256 * 3), AITile.TRANSPORT_RAIL)); + print(" HasTransportType(): " + AITile.HasTransportType(6200 + (256 * 4), AITile.TRANSPORT_RAIL)); + print(" BuildRailTrack(): " + AIRail.BuildRail(14706, 14705, 12907)); + print(" HasTransportType(): " + AITile.HasTransportType(13421, AITile.TRANSPORT_RAIL)); + print(" HasTransportType(): " + AITile.HasTransportType(14191, AITile.TRANSPORT_RAIL)); + print(" RemoveRail(): " + AIRail.RemoveRail(12907, 13163, 14706)); + print(" HasTransportType(): " + AITile.HasTransportType(13421, AITile.TRANSPORT_RAIL)); + print(" HasTransportType(): " + AITile.HasTransportType(14191, AITile.TRANSPORT_RAIL)); + print(" BuildRailTrack(): " + AIRail.BuildRailTrack(61533, AIRail.RAILTRACK_NW_SW)); + print(" BuildRailTrack(): " + AIRail.BuildRailTrack(61533, AIRail.RAILTRACK_NE_SE)); + print(" BuildRailTrack(): " + AIRail.BuildRailTrack(61533, AIRail.RAILTRACK_NW_NE)); + print(" BuildRailTrack(): " + AIRail.BuildRailTrack(61533, AIRail.RAILTRACK_SW_SE)); + print(" BuildRailTrack(): " + AIRail.BuildRailTrack(61533, AIRail.RAILTRACK_NE_SW)); + print(" DemolishTile(): " + AITile.DemolishTile(61533)); + print(" BuildRailTrack(): " + AIRail.BuildRailTrack(61533, AIRail.RAILTRACK_NE_SW)); + print(" BuildRailTrack(): " + AIRail.BuildRailTrack(61533, AIRail.RAILTRACK_NW_SE)); + print(" BuildRailTrack(): " + AIRail.BuildRailTrack(61533, AIRail.RAILTRACK_NW_NE)); + print(" BuildRailTrack(): " + AIRail.BuildRailTrack(61533, AIRail.RAILTRACK_SW_SE)); + print(" DemolishTile(): " + AITile.DemolishTile(61533)); + print(" BuildRailTrack(): " + AIRail.BuildRailTrack(61533, AIRail.RAILTRACK_NW_SE)); + + 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)); + + print(" Waypoint"); + print(" BuildRailTrack(): " + AIRail.BuildRailTrack(12646, AIRail.RAILTRACK_NW_SE)); + print(" BuildRailTrack(): " + AIRail.BuildRailTrack(12648, AIRail.RAILTRACK_NE_SW)); + print(" BuildRailTrack(): " + AIRail.BuildRailTrack(12650, AIRail.RAILTRACK_NW_NE)); + print(" BuildRailWaypoint(): " + AIRail.BuildRailWaypoint(12644)); + print(" BuildRailWaypoint(): " + AIRail.BuildRailWaypoint(12646)); + print(" BuildRailWaypoint(): " + AIRail.BuildRailWaypoint(12648)); + print(" BuildRailWaypoint(): " + AIRail.BuildRailWaypoint(12650)); + print(" IsRailWaypointTile(): " + AIRail.IsRailWaypointTile(12644)); + print(" IsRailWaypointTile(): " + AIRail.IsRailWaypointTile(12646)); + print(" IsRailWaypointTile(): " + AIRail.IsRailWaypointTile(12648)); + print(" IsRailWaypointTile(): " + AIRail.IsRailWaypointTile(12650)); + print(" RemoveRailWaypointTileRectangle():" + AIRail.RemoveRailWaypointTileRectangle(12644, 12646, false)); + print(" RemoveRailWaypointTileRectangle():" + AIRail.RemoveRailWaypointTileRectangle(12648, 12650, true)); + print(" IsRailWaypointTile(): " + AIRail.IsRailWaypointTile(12644)); + print(" IsRailWaypointTile(): " + AIRail.IsRailWaypointTile(12646)); + print(" IsRailWaypointTile(): " + AIRail.IsRailWaypointTile(12648)); + print(" IsRailWaypointTile(): " + AIRail.IsRailWaypointTile(12650)); + print(" HasTransportType(): " + AITile.HasTransportType(12644, AITile.TRANSPORT_RAIL)); + print(" HasTransportType(): " + AITile.HasTransportType(12646, AITile.TRANSPORT_RAIL)); + print(" HasTransportType(): " + AITile.HasTransportType(12648, AITile.TRANSPORT_RAIL)); + print(" HasTransportType(): " + AITile.HasTransportType(12650, AITile.TRANSPORT_RAIL)); + print(" DemolishTile(): " + AITile.DemolishTile(12648)); + print(" DemolishTile(): " + AITile.DemolishTile(12650)); +} + +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(6, 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 0000000000..360e1c23b0 --- /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 0000000000..e93b2e2343 --- /dev/null +++ b/bin/ai/regression/tst_regression/result.txt @@ -0,0 +1,9335 @@ + +--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(): + VT_RAIL: (null : 0x00000000) + VT_ROAD: (null : 0x00000000) + VT_WATER: (null : 0x00000000) + VT_AIR: (null : 0x00000000) + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxLength(): -1 + GetMinLength(): -1 + Bridge 0 + IsValidBridge(): true + GetName(): + VT_RAIL: Wooden rail bridge + VT_ROAD: Wooden road bridge + VT_WATER: Aqueduct + VT_AIR: (null : 0x00000000) + GetMaxSpeed(): 32 + GetPrice(): 450 + GetMaxLength(): 66 + GetMinLength(): 2 + Bridge 1 + IsValidBridge(): true + GetName(): + VT_RAIL: Concrete rail bridge + VT_ROAD: Concrete road bridge + VT_WATER: Aqueduct + VT_AIR: (null : 0x00000000) + GetMaxSpeed(): 48 + GetPrice(): 630 + GetMaxLength(): 4 + GetMinLength(): 2 + Bridge 2 + IsValidBridge(): true + GetName(): + VT_RAIL: Steel girder rail bridge + VT_ROAD: Steel girder road bridge + VT_WATER: Aqueduct + VT_AIR: (null : 0x00000000) + GetMaxSpeed(): 64 + GetPrice(): 811 + GetMaxLength(): 7 + GetMinLength(): 2 + Bridge 3 + IsValidBridge(): true + GetName(): + VT_RAIL: Reinforced concrete suspension rail bridge + VT_ROAD: Reinforced concrete suspension road bridge + VT_WATER: Aqueduct + VT_AIR: (null : 0x00000000) + GetMaxSpeed(): 80 + GetPrice(): 946 + GetMaxLength(): 12 + GetMinLength(): 4 + Bridge 4 + IsValidBridge(): true + GetName(): + VT_RAIL: Steel suspension rail bridge + VT_ROAD: Steel suspension road bridge + VT_WATER: Aqueduct + VT_AIR: (null : 0x00000000) + GetMaxSpeed(): 96 + GetPrice(): 1042 + GetMaxLength(): 66 + GetMinLength(): 5 + Bridge 5 + IsValidBridge(): true + GetName(): + VT_RAIL: Steel suspension rail bridge + VT_ROAD: Steel suspension road bridge + VT_WATER: Aqueduct + VT_AIR: (null : 0x00000000) + GetMaxSpeed(): 112 + GetPrice(): 1081 + GetMaxLength(): 66 + GetMinLength(): 5 + Bridge 6 + IsValidBridge(): true + GetName(): + VT_RAIL: Steel cantilever rail bridge + VT_ROAD: Steel cantilever road bridge + VT_WATER: Aqueduct + VT_AIR: (null : 0x00000000) + GetMaxSpeed(): 160 + GetPrice(): 1261 + GetMaxLength(): 9 + GetMinLength(): 5 + Bridge 7 + IsValidBridge(): true + GetName(): + VT_RAIL: Steel cantilever rail bridge + VT_ROAD: Steel cantilever road bridge + VT_WATER: Aqueduct + VT_AIR: (null : 0x00000000) + GetMaxSpeed(): 208 + GetPrice(): 1306 + GetMaxLength(): 10 + GetMinLength(): 5 + Bridge 8 + IsValidBridge(): true + GetName(): + VT_RAIL: Steel cantilever rail bridge + VT_ROAD: Steel cantilever road bridge + VT_WATER: Aqueduct + VT_AIR: (null : 0x00000000) + GetMaxSpeed(): 240 + GetPrice(): 1396 + GetMaxLength(): 11 + GetMinLength(): 5 + Bridge 9 + IsValidBridge(): true + GetName(): + VT_RAIL: Steel girder rail bridge + VT_ROAD: Steel girder road bridge + VT_WATER: Aqueduct + VT_AIR: (null : 0x00000000) + GetMaxSpeed(): 256 + GetPrice(): 1351 + GetMaxLength(): 4 + GetMinLength(): 2 + Bridge 10 + IsValidBridge(): false + GetName(): + VT_RAIL: (null : 0x00000000) + VT_ROAD: (null : 0x00000000) + VT_WATER: (null : 0x00000000) + VT_AIR: (null : 0x00000000) + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxLength(): -1 + GetMinLength(): -1 + Bridge 11 + IsValidBridge(): false + GetName(): + VT_RAIL: (null : 0x00000000) + VT_ROAD: (null : 0x00000000) + VT_WATER: (null : 0x00000000) + VT_AIR: (null : 0x00000000) + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxLength(): -1 + GetMinLength(): -1 + Bridge 12 + IsValidBridge(): false + GetName(): + VT_RAIL: (null : 0x00000000) + VT_ROAD: (null : 0x00000000) + VT_WATER: (null : 0x00000000) + VT_AIR: (null : 0x00000000) + GetMaxSpeed(): -1 + GetPrice(): -1 + GetMaxLength(): -1 + GetMinLength(): -1 + Bridge 13 + IsValidBridge(): false + GetName(): + VT_RAIL: (null : 0x00000000) + VT_ROAD: (null : 0x00000000) + VT_WATER: (null : 0x00000000) + VT_AIR: (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(): 136 + 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(): 381 + 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(): 471 + 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(): 479664 + 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(): 465070 + +--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(): 459675 + 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 + HasTransportType(): false + HasTransportType(): false + BuildRailTrack(): true + RemoveRailTrack(): false + RemoveRailTrack(): true + BuildRail(): true + HasTransportType(): true + HasTransportType(): false + RemoveRail(): true + HasTransportType(): true + HasTransportType(): false + BuildRailTrack(): true + HasTransportType(): true + HasTransportType(): true + RemoveRail(): true + HasTransportType(): false + HasTransportType(): false + BuildRailTrack(): false + BuildRailTrack(): false + BuildRailTrack(): true + BuildRailTrack(): true + BuildRailTrack(): false + DemolishTile(): true + BuildRailTrack(): true + BuildRailTrack(): false + BuildRailTrack(): false + BuildRailTrack(): false + DemolishTile(): true + BuildRailTrack(): 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 + Waypoint + BuildRailTrack(): true + BuildRailTrack(): true + BuildRailTrack(): true + BuildRailWaypoint(): false + BuildRailWaypoint(): true + BuildRailWaypoint(): true + BuildRailWaypoint(): false + IsRailWaypointTile(): false + IsRailWaypointTile(): true + IsRailWaypointTile(): true + IsRailWaypointTile(): false + RemoveRailWaypointTileRectangle():true + RemoveRailWaypointTileRectangle():true + IsRailWaypointTile(): false + IsRailWaypointTile(): false + IsRailWaypointTile(): false + IsRailWaypointTile(): false + HasTransportType(): false + HasTransportType(): false + HasTransportType(): true + HasTransportType(): true + DemolishTile(): true + DemolishTile(): true + +--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): 6 + GetStationID(34411): 65535 + GetStationID(33411): 6 + 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 0000000000..60f3e4a4a7 --- /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 0000000000..20e594766f --- /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 0000000000000000000000000000000000000000..ef551c74ff8f74202cb30e88b6c063442b44ed78 GIT binary patch literal 94348 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%0A0$MM2b8 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

C`2_#4zuLKQj|6^Mm=I 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 literal 0 HcmV?d00001 diff --git a/docs/landscape.html b/docs/landscape.html new file mode 100644 index 0000000000..d4d8f7efeb --- /dev/null +++ b/docs/landscape.html @@ -0,0 +1,1620 @@ + + + + + + + + OpenTTD Landscape Internals + + + + + +

+ 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
  • +
  • m8 bits 5..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
      • +
      • m5 bit 5: set if crossing lights are on
      • +
      • m5 bit 4: pbs reservation state
      • +
      • m5 bit 0: direction + + + + + + + + + +
        0  road in the X direction, rail in Y
        1  road in the Y direction, rail in X
        +
      • +
      • m7 bits 4..0: owner of the road type 0 (normal road)
      • +
      • m8 bits 5..0: railway track type
      • +
      +
    • +
    +
  • +
  • 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 6..5: water class (sea or land)
  • +
  • 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)
  • +
  • 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)
  • +
  • m8 bits 5..0: track type for railway stations/waypoints
  • +
+
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
  • +
  • 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
  • +
  • m8 bits 5..0: track type for railway
  • +
+
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 0000000000..cef6c2f2c7 --- /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 0000000000..4948366e65 --- /dev/null +++ b/docs/landscape_grid.html @@ -0,0 +1,397 @@ + + + + + + OpenTTD Landscape Internals - #2 + + + +

Landscape

+Nine 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
  • +
  • m8 - 16 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)m8 (16)
bits7654 32107654 32107654 3210FEDC BA98 7654 32107654 32107654 32107654 32107654 32107654 3210FEDC BA98 7654 3210
0groundXXXX XXXXXXXX XXXXOOO~ ~~~~OOOO OOOO OOOO OOOOXXXX OOOOXXXX XXOOXXXX XXXXOOOX XXOOOOOO OOOOOOOO OOOO OOOO OOOO
farmland-inherit--inherit--inherit-XXXX XXXX XXXX XXXXXXXX XXXX-inherit--inherit-OOOX XXOOOOOO OOOOOOOO OOOO OOOO OOOO
1railXXXX XXXXXXXX XXXXOOOX XXXXOOOO XXXX OOOO OOOOOOOO OOOOOOOO XXXXXXXX XXXXOOOO OOOOOOOO OOOOOOOO OOOO OOXX XXXX
rail with signals-inherit--inherit--inherit-OOOO XXXX XXXX XXXXXXXX OOOOXXXX XXXX-inherit-OOOO OOOOOOOO OOOO-inherit-
depot-inherit--inherit--inherit-XXXX XXXX XXXX XXXX-inherit-OOOO XXXXXXOX OOXXOOOO OOOOOOOO OOOO-inherit-
2roadXXXX XXXXXXXX XXXXOOOX XXXXXXXX XXXX XXXX XXXXXXXX XXXXOOOO OOOOXXXX XXXXOOXX XOOOXXXO XXXXOOOO OOOO OOOO OOOO
level crossing-inherit--inherit--inherit--inherit-XXXX OOOOOOOO OOOOXXXX OOOXOOXX XOOOXXXX XXXXOOOO OOOO OOXX XXXX
road depot-inherit--inherit--inherit--inherit-XXXX OOOOOOOO OOOOXXOO OOXXOOOO OOOOXXXO XXXXOOOO OOOO OOOO OOOO
3houseXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXX XXXX XXXXXXO~ ~~XXXXXX XXXXXXXX XXXXXXXX XXOOXXXX XXXXOOOO OOOO OOOO OOOO
4treesXXXX XXXXXXXX XXXXOXX~ ~~~~OOOO OOOX XXXX XXXX~~XX XXXXOOOO OOOOXXOO OXXXOOOO OOOOOOOO OOOOOOOO OOOO OOOO OOOO
5rail stationXXXX XXXXXXXX XXXXOXXX XXXXXXXX XXXX XXXX XXXXXXXX OOOOXXXX XXXXXXXX XXXXOOXX XXOOXXXX XXXXOOOO OOOO OOXX XXXX
rail waypoint-inherit--inherit--inherit--inherit--inherit--inherit--inherit--inherit--inherit--inherit-
road stop-inherit--inherit--inherit--inherit-XXXX OOOOOOOO OOOO~~~~ ~XXXOOXX XOOOXXOX XXXXOOOO OOOO OOOO OOOO
dock-inherit--inherit--inherit--inherit-OOOO OOOOOOOO OOOO~~~~ ~XXXOOXX XOOOOOOO OOOOOOOO OOOO OOOO OOOO
airport-inherit--inherit--inherit--inherit-XXXX OOOOOOOO OOOOXXXX XXXXOOXX XOOOXXXX XXXXOOOO OOOO OOOO OOOO
buoy-inherit--inherit--inherit--inherit-OOOO OOOOOOOO OOOO~~~~ ~~~~OOXX XOOOOOOO OOOOOOOO OOOO OOOO OOOO
oilrig-inherit--inherit--inherit--inherit-OOOO OOOOOOOO OOOO~~~~ ~~~~OOXX XOOOOOOO OOOOOOOO OOOO OOOO OOOO
6sea, shoreXXXX XXXXXXXX XXXXOXXX XXXXOOOO OOOO OOOO OOOOOOOO OOOOOOOO OOOOX~~X XXXXOOOO OOOOOOOO OOOOOOOO OOOO OOOO OOOO
canal, river-inherit--inherit--inherit-OOOO OOOO OOOO OOOOOOOO OOOOXXXX XXXX-inherit-OOOO OOOOOOOO OOOOOOOO OOOO OOOO OOOO
shipdepot-inherit--inherit--inherit-XXXX XXXX XXXX XXXXOOOO OOOOOOOO OOOO-inherit-OOOO OOOOOOOO OOOOOOOO OOOO OOOO OOOO
8industryXXXX XXXXXXXX XXXXXXXO XXXXXXXX XXXX XXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXOOXX XXOOXXXX XXXXOOOO OOOO OOOO OOOO
9tunnel entranceXXXX XXXXXXXX XXXXOOOX XXXXOOOO OOOO OOOO OOOOXXXX OOOOOOOO OOOOXOOX XXXXOOOO OOOOXXXX XXXXOOOO OOOO OOXX XXXX
bridge ramp-inherit--inherit--inherit-OOOO OOOO OOOO OOOO-inherit-OOOO OOOO-inherit-OOXX XXOO-inherit--inherit-
AobjectsXXXX XXXXXXXX XXXXOXXX XXXXXXXX XXXX XXXX XXXXXXXX XXXXOOOO OOOOXXXX XXXXOOOO OOOOXXXX XXXXOOOO OOOO OOOO OOOO
+ + + diff --git a/docs/linkgraph.txt b/docs/linkgraph.txt new file mode 100644 index 0000000000..2515185a4a --- /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 0000000000..62314d7b4c --- /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 + higher. 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 automatically 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 automatically 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 0000000000..f43ea7edd7 --- /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 0000000000..45fe5f879e --- /dev/null +++ b/docs/obm_format.txt @@ -0,0 +1,124 @@ +; +; 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'. +; If you want to load music from the MPS DOS music driver "cat" format, +; specify just the name of the .cat file the song is located in, then +; fill out the "catindex" section. +[files] +; The theme song for OpenTTD +theme = THEME_SONG.GM +; The songs in the 'old style' category +old_0 = GM.CAT +old_1 = GM.CAT +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. +; You don't need to fill this out for "cat" format music, the song names +; are loaded directly from the file in that case. +[names] +THEME_SONG.GM = Tycoon DELUXE Theme + +; If you are loading music from the DOS version "cat" format, specify +; which index into the file the song has. +[catindex] +old_0 = 1 +old_1 = 3 + +; 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 + +; If a song needs to have parts of the start or end cut off to avoid long +; silences, you can specify MIDI tick codes for start:end of the actual +; music part for each file here. +; Not all music drivers might support this feature. +[timingtrim] +THEME_SONG.GM = 768:53760 + +; 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 0000000000..21bb285b7f --- /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 0000000000..4e04be32c1 --- /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 0000000000000000000000000000000000000000..26cb20fbbd9869721fc4f9482f50afbcbb08ec17 GIT binary patch literal 2126 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ℜ>)+p=$@}{Fu6;P(WTvw>SWo<(rzs3py?es46A2ELg^E@<*|%t^JOX-MbA(M0ZWtw5Tp`_m=qmzxe&+Z>H|$*fjmXTl?fH99>F|fiF|O_I`hSx*S43scw=DB9zr|ORZ@~Ab?c^Hynd?=)oyc`v zcyXtyg-T_=fkH`3?WIk8n*-~GYR~NIut>j=vE{36(xsK%A!X;*6z_`P|4T^y^j^xL6=cY%|_hHUIVgy2EW> zUmxGMZ&%ybsPlfa*ekF1?1}%YKK<^YZ#7S4tRG!G=fJM>WcOr4wu6HE@}lmqjtO&G zXYtzRn~{kR$10gN&vKzVa(YBP{`;%{r5e=_4_O4to$o{V(oRyKJ~xfn12*Kyl%{VW&8a9 z?QU1XuWyNa&AKfm#K(7O{9h60AD?7)JI~--kjwGYoSCz>lzn~aY(de+x(c})Um11( z*~Qna_5Heb^Sk;SF(QZH|gw1R6jYV zKJdc#mF6#1^b~l{&3GkR^L`Fb=JunECu8pcbVq?2d{rH_J-+#ZjMd2kEgl_&XU?}eEo0L zlKC@M#D|!RzEcT`Hj*IdGFte zxb|L7o4iO#uVF&0z?@#^P5N^0+1~mW{QtEn!lAtE7u&r@OM6#%j@tig^K$F^ zk83~3*;=@!y`F0RqA2FTnQfw6$DYN?h&#M+i@Nn`_lf5=iSF(<7bH(OCKf*b^3gA6 zH$O99vTyInUss>wFsX(Uz9?4-*&9+0oXdDdP9{=gfbVZybXCCf#{A zAuW92b@P5%?cB4P1)KjJ-5+7#u)pg3nTxZn$``Kd;C8uqQR9K#uau64_WqD#tWGmj z9BpzL-*^4Kep=;aUJ%pVA8grn#)}KTzV*Gf-mctqlWs+yERV{!a$!C08?TqnWt>!Q zC{n_9-aap@;IYj&l?kWrNLfEFl(SAZee7J?VN+3MRC;aA)6id6rM=&aC6&fXiobYv zag)pc?I-hYR9bA)owUPYg>Ti>hYi+mCkHi!9%^2>Yp47AxX*Xnu5ULF-(U5tBHFDa zGsA_iq-3+*_MJLGOAPK>`Omk@&RYHT`1!e?y;6(!JekT}oSao8XT5yKw*ooqU6(xN z_P9;`bS1O)_tkc}XD@tr7cG1zD&FCE_42cW|1@3+i*uxk8TGF+;0*sJ_%hRX`&E83 z&)VwZudB~LOFLHlrq4mmXgkO3`Q4vok|cgl{lWT2aLIJBhe11Ai?&WmmzGWVBzwB@ zjmx(pIh$}z|GjCB>+8O%+!v3jQ?CjQJH{%veNFg%rTsPkA3KCMin`W5W>PF$Q=)JF zS;*fb`q|I3q4)2_{C!pVPNuk;pI^=@OWJeZmFeM=Y$w^M%jtYBTsKi~bM~Cio+`&v z-_Jds*H!V@rs7_>%P*H}m)ZSy7wtTfp!JBUTCo15qW0dqo2=gY3;cciuaGh9gUrRo z`R7#fPyPD#>{U4bq0PQ`l$#0@Z|vSTr={lk$?0q6rl0;hxnja}&*W!ypP$;4Sud-6 zZ&N1w^>p*`U#!<-l>fdu%o-jm_v&9^h#O!DomO&QL>>|rdJ2;KCmQRjoIzoo;^qb@Te2 zU+(P84A*eaW;Ef~ zZF>4$>BIi#!X6AtlaxKA=O#MO|JIrQBQ{>)>s#L|>*s}KzSWStsmxAdC)(|@p|w0vIe&6+lrsjA!g zIORL^%I_}R{H`_l{ym+)uUPxpALa`^6OjM_to!P zj|(5a|82u{_I`Gw-+m`w+aLFR9i7*Id-B5EpH919{V6-6VE^USKXaeh?E5x9PK)|C zT(5e{n`rs&+{F^clo{v8kIgPKvzXX*#~8B>6$ZZ`P3e_iogE zt^HWBc7MU|PaDML^51X0^*Aw3wD`^zy|YnCkGPEX$JWcPk$S#y_NUgzwv8YE#Jewk zysz?u{QsWSzTfx^Z64VhjB)_VnM<4&R1#9rYU=)3VLa{S(xAeQ0HVe!~7= zS`~Y)UCxh}2z&4`W#U`i*4pPgUS3+eUA2(acz^6`_qU6m+LY9Zepz!y(pc7LOWal&AvJ;SK9MS(RqtGjR5HJ9P8HCb5Mz7R*KabP^sA;-`S}6+ ze=&ZjQ2Mj!_^FCL>5=SvSA3T-pY%T5H~jDO?ZquIpKkd6JS2F#Zu4S^%q#m8Ja>i5 z{W1MqveC#m{C;V$Mx^zQ<~i(7+UD$fF!#~K$AJQ}Q*W%bC|@{lan;)Aht6=X+_zWo z?<@9WkGIC{vgr9(vHNj?dbq24@g0wS`f;zq=HK_@(XV{7tj6)v4dqxDuP?jjh0kRF zzy4W9@{J>+)1qR{cPsJRcQu!(zOdWlwk_+GSLT0L*xfzT^a>t`G_m6;Q( z94M_;CT{(S>HJ0QxfA!s%(knV`dV`Hy1n~iRdSO*etCB2abTDD(TY8qu1;)Q^mHT4 zYA^hJEA`dO-S?+c!==u-cc0&$*qeCBWDa}%%hFq>b0;pj;#IQw(z~nNk(1gRXS|)X zvhzaE$_X2+mFN9_7ZS^Fz4zF!veX^RE>=_(Kl~VVzijoBoeh_lJnq!1y!?#cbpKyR z-M1+_Y7TCT*K)2{x}^DF(SsC8^URKCGtN!_!1DZV!Xg%i>qlogFR<%+WV8ChHw%~G zQd{rOQLk>_yn5dHY{PPMak=$hubLl!o9V!G;(K-0%=_mOcAreP|7iC7_`BNpn6hPm zcD9%LXp4rQ;}+bUGFR~M{eu&K2HcXA(A5{KV~P7eql`WBJdb@z?e0SxnwjFCAA9`r zZ0qst+N);^r6ymCdwH&M>)HJJfa8^KIBw3f`}yy-=+3ZvJ7;gnZrP;ilD0~y&H@{~-1rt|ML_BA`(@Y-{}rStXe!dJOJ{GY|*pRZ>V_d0cZ%bU%WOB;Wk4WE6# zZtlrsakHyOo~e3H;yYiIM*6pow&%1ohy6n2&%{+&lu6&=+b|LBP)E%LX*;a`& z#XJH|xCX~(&YCa2b>99tyO(=DY3r7s`9q^+RidqQdGqz{;&YZAzC4?|pZ($9?B`dl z_t#Fnrq(~VrdBfd=vn8<`^t}fJT+rlxo5X`UEukj;g=HCMP9JxEqUw8y*2oD)v+gR ztMk*@x7_>yN;I3N>&hPc^Nsx<|5;Bnh22jM&gcF*r$>2*viSk4XQ%#H8KoFq`Vzzz zXrZxef8NgPS9i~LEolzhy3X9~c*EDX1yeSkZ3o4qeZ~G?jnB5oXTSWa_`eH2-#++3<%#D3`v)EY ztyha!JD7T7e4Z2^>(n)t(2Y7<%k*%Tfy(||iPx6m3$ki=^Q`@N@`d`(3F0msPIn-7zUN0Z!xa+rqvGO^urp3PP%gv)}|6KTdn|-x@{+F-87RNub#y`7}GF#F= zf7`DgjnB99TiWlvc)dSX?(tr>V{-TZtSNb+Kdo@4&(BxU+ ze&j_IUke(a*P^Uk{JJ_u_qh;$zT3 z75SH@e!kuL@bwD){4d}4Klu2??cvAZlKYmqGakn#*H$jxUvGS6d-~BPG3CkHRu$ew zIwz-2oc)m}x5`^!wSHmGot$lo6@T_$Y(A4OziHo|i$6Jf*XM^{5;pYXEA;)kOfbMh zpv3ppeiqfG;oOTv3?i7qp9(0+X50Lm_p12TmUU~vT6_)m$EI2=d2(##{+x8Le;to! zHJ&Q`w7%elV=hE}x)FT*@q5V{zu74#`Qqa5y{KWiT3{3NYggkr;TIv@lRmEGS-6zP zVU4IEBh&Qy4UU_(KHa#y_xO3)B0uS>9-csuj+VB^50|Z<9sNLdmSFd}h_W<(m8tP= zr_z@kT7JytTgk^CmAl$3b5}%5Z2`Ne_xRz-`|{N4bQb$4JP$n7sdJ>Ki0MkHoN;RW zrKPS{XB?lWCubk;Zh9_L8lqv<$BK%b>!r_`uDoCNSV_Rs)6~{1_H%fsyIgfw#h+5s z^O?O0@6h1n$*z%C1_)kss=yHj%q?+kCX{N(U$X#f89^|KA{CkpPG&C$Ci*)}X+u3D?&&z$wI zwLahexc_d}dn=y2?W@mbcKhVtOgjy-ByR2c*+Rm7rdHm1<}X)9)yq{&Rs5+j&Rcu_ zPuUiQ*ICci{@VtIl=?|$|5$d~J>$=xZ>wtW`m9&&yi;Htt7aFt_npl*kq;GHs}@-1 zCW_2?cF?!_Jil4!nxCHprQ+t>ImB=0Ty${CN_{P>KS$f99=Cf`)8NQ{^zEjyQkgrM zTe}0c+dhe_XgbyM$NROa?{)bFA3xt_fA!ieUh##k>_OSQ_??1}KSt?GWcb~QJZ%-g z#UF94dWPna&29$rpH}FG=r_JNdtH8kYvk(eZ`Ls`JJx%I9JZ- z^{!uMI=ge!swRJ9�Wl~8;4!phd|E2Z}CD>9vLueR&kT;X*0w15Ni?iD{$diG`6 zTmB0ypKr6jeSPdDaer&$qMZ zx8>ASJ^pUK&BoTO;=_U3yFRmh_gHk*K5Z-g*KqIm+0JA?c}=;0hq(2(Y=6J(_P*MF z`+v7yT;2ZtV6yr4ZFxC2cN8X{{vK_%t&deMX6yRdC+D4V{@@*Tb;Z}I($9V}&v|L9 z&gUX;DR-~?)ltLM`S)W+!*UtWz6ny&f{ralQ%dYuKoA)!y-C4a} zdikXVHWvDpQ*}OC&S{o4(5ijvR`8GMcw3p%7m*JizJ23b#a_Dpd-2Z1E8Dl*?OvHG zZ20@~m)H88pOPEckJsLva&pGgcX2tF)|NizkSqVCwV}^{@A^9(=j6lo9&d|@s;Kz= zj%(Ha`2SVr;q|rEucuw}^|$~1cYj9a%`KV2nm?9DyUX%F+n1M?rYLALVad)LjnSv| zm8zysjLDi>7Qb`iJo{xw7Ro5;+SHW$e5>8v{QY(O`zL>5?tXontGibB{3OrsU%p4b z`2PQI^Z(^bOTTYDuYY7cT#0r1?4X`&8+dKeOkm$<3QE z_eI?Qs-&{x>v!*~EzUkY?d*{ky3tWl|B5d2o8{%)wGpc@m~Odf{cM$+9xrE1=G-B0 zsG<0Hii(%pot+}j_oU9|=GUJ*_eI?IDxUOkwe#N);CtLG#GBa=PsC?{Z z^x93HKTIY(Nu%xMuCPn1PppX6{xjF`cVlVI#M2(Zb3RYY)w8MjzVEu$i@5KkC@uz1tFYNs~LqIPgqK$M?7iS(eFntToS6P7cTqe)#aWT)Ol=pYK)IcDt0>$FJDF zulDt{Y1`!UZeF?d>C3bIe@^Sp_Bg@c_558$+=n~c5+5C`{HA*P^JCw~VR};^_{IB8 z&{TQL*d>4VxNf7$d9U7*bJ0E5OoZk7Zpc*TrS7`Ed0unC&zgnjetk>dmQ#`D{F>i9 z|JII~d%pGB-`J6wV6)xV()!k)w>RHr{r;SL`|9Vd4-fXdn|UE=-s{`dXZ!De{BtWk zy5mHyq@F}RhB&OX$fTyp+6 zcZL7cKNUh!*0<)omEOKRNjY_%`n9;|6KhIiJogtIEiLcT`L$8;Q_daU@^jHVhgL5; zba>{gE&H0@nXXsA>c=E-vCr!D?d{tHjko1wRi_z8maJ8IvYoHx`MVn*ZT{Z6=VnsB z?rddUwQog%GrqMM;jF98^sqqQe#~7NOF-rd%>&YkN>93 zU-9hC^mxbbQP&T5rap~av3}p)t+|J%Esvg8`K9ct`)3(|LvZK&>H8LEScJynPrUcmn^B+lYbz> zWo_u?Z>RlV{QL2E>zeP9i3+QpU%wW7|DVt8Yw4cL^KWk2+1p~U$aMC;?GLM^jik*& zjxH{LQ<3+(zi!W5k1uzMU6v_+e6a7uyqR)(@6?a^{HisZq?N++q`^MmQ?KN zd@);NZ_%vn@pV4mlRhN!zRu))Q(@F{O)P7Detp{OYyWrc{F?dbTYBA=nI_eze|>%3 z`Re{}xxZhIFW&y!y6(^8x7Kxc+)m9{@~OWpN1loQUH`k2Ukc`n+COEn*YVW?<;@kDL%f8-RzC9;T^-=!4 zJ^xOA^{>nS`~8O-&-}>i-2V4A)*dfQI`h`Pj;|y?`}V>s@w|QP;m+R;+@-QO?q9qA z?%Q1tfsj0##WuP&c6Ex<%aeDUy`wK*qQ2_-mU$=qT8)Yn`n^Rvu^L3dz z?bE2|NUjy6L-0)V0V9j`H8sV+TYK%rEe>; zXqEZy>+. + + +# Arguments given? Show help text. +if [ "$#" != "0" ]; then + cat <\t\t\t +VERSION + a string describing what version of the code the current checkout is + based on. + This also includes the commit date, 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. +ISODATE + the commit date of the revision this checkout is based on. + The commit date may differ from the author date. + This can be used to decide upon the age of the source. + + If no timestamp 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. + + A value of 1 means that the modified status is unknown, because this + is not an git checkout for example. + +HASH + the git revision hash + +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/.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` + SHORTHASH=`echo ${HASH} | cut -c1-10` + ISODATE=`LC_ALL=C git show -s --pretty='format:%ci' HEAD | "$AWK" '{ gsub("-", "", $1); print $1 }'` + BRANCH="`git symbolic-ref -q HEAD 2>/dev/null | sed 's@.*/@@'`" + TAG="`git name-rev --name-only --tags --no-undefined HEAD 2>/dev/null | sed 's@\^0$@@'`" + + if [ "$MODIFIED" -eq "0" ]; then + hashprefix="-g" + elif [ "$MODIFIED" -eq "2" ]; then + hashprefix="-m" + else + hashprefix="-u" + fi + + if [ -n "$TAG" ]; then + VERSION="${TAG}" + ISTAG="1" + if [ -n "`echo \"${TAG}\" | grep \"^[0-9.]*$\"`" ]; then + ISSTABLETAG="1" + else + ISSTABLETAG="0" + fi + else + VERSION="${ISODATE}-${BRANCH}${hashprefix}${SHORTHASH}" + ISTAG="0" + ISSTABLETAG="0" + 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" + HASH="" + SHORTHASH="" + BRANCH="" + ISODATE="" + TAG="" + VERSION="" + ISTAG="0" + ISSTABLETAG="0" +fi + +echo "$VERSION $ISODATE $MODIFIED $HASH $ISTAG $ISSTABLETAG" diff --git a/known-bugs.txt b/known-bugs.txt new file mode 100644 index 0000000000..342e75305d --- /dev/null +++ b/known-bugs.txt @@ -0,0 +1,411 @@ +OpenTTD's known bugs +Last updated: 2019-09-16 +Release version: 1.9.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 https://github.com/OpenTTD/OpenTTD/issues +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 + +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 (partially) fix this is by + adding spaces to the custom name. + +Clipping problems [#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 [#383] [#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 [#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 [#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 [#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 [#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 [#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 [#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 GNOME's + and KDE'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 macOS [#3447]: + Video handling with (lib)SDL under macOS is known to fail on some + versions of macOS 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 macOS. + +Train crashes entering same junction from block and path signals [#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 run in a VM using Parallels Desktop [#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 macOS 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 macOS. + +Entry- and exit signals are not dragged [#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 + convenient 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 [#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. + +(Temporary) wrong colours when switching to full screen [#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 + +Can't run OpenTTD with the -d option from a MSYS console [#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 [#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.md 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-bit + 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. + +Train does not crash with itself [#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 [#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 [#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 [#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 [#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.md. + +Mouse cursor going missing with SDL [#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. + +Trains might not stop at platforms that are currently being changed [#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 theorder list (see #5684). + +Inconsistent catchment areas [#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. + +Some houses and industries are not affected by transparency [#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. + +Involuntary cargo exchange with cargodist via neutral station [#6114]: + When two players serve a neutral station at an industry, a cross-company + chain for cargo flow can and will be established which can only be + interrupted if one of the players stops competing for the ressources of + that industry. There is an easy fix for this: If you are loading at the + shared station make the order "no unload" and if you're unloading make + it "no load". Cargodist will then figure out that it should not create + such a route. diff --git a/media/baseset/no_music.obm b/media/baseset/no_music.obm new file mode 100644 index 0000000000..fd75cfef32 --- /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 0000000000..e9d5741a0c --- /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 0000000000..f9db843af1 --- /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 = ORIG_EXTRA.GRF + +[md5s] +TRG1.GRF = 9311676280e5b14077a8ee41c1b42192 +TRGI.GRF = da6a6c9dcc451eec88d79211437b76a8 +TRGC.GRF = ed446637e034104c5559b32c18afe78d +TRGH.GRF = ee6616fb0e6ef6b24892c58c93d86fc9 +TRGT.GRF = e30e8a398ae86c03dc534a8ac7dfb3b6 +ORIG_EXTRA.GRF = + +[origin] +default = You can find it on your Transport Tycoon Deluxe CD-ROM. +ORIG_EXTRA.GRF = This file was part of your OpenTTD installation. diff --git a/media/baseset/orig_dos.obm b/media/baseset/orig_dos.obm new file mode 100644 index 0000000000..9920bfdbe1 --- /dev/null +++ b/media/baseset/orig_dos.obm @@ -0,0 +1,76 @@ +; $Id$ +; +; This represents the original music as on the Transport +; Tycoon Deluxe for DOS CD. +; +[metadata] +name = original_dos +shortname = TTDD +version = 1 +!! description STR_BASEMUSIC_DOS_DESCRIPTION + +[files] +theme = gm.cat +old_0 = gm.cat +old_1 = gm.cat +old_2 = gm.cat +old_3 = gm.cat +old_4 = gm.cat +old_5 = gm.cat +old_6 = gm.cat +old_7 = gm.cat +old_8 = +old_9 = +new_0 = gm.cat +new_1 = gm.cat +new_2 = gm.cat +new_3 = gm.cat +new_4 = gm.cat +new_5 = gm.cat +new_6 = gm.cat +new_7 = +new_8 = +new_9 = +ezy_0 = gm.cat +ezy_1 = gm.cat +ezy_2 = gm.cat +ezy_3 = gm.cat +ezy_4 = gm.cat +ezy_5 = gm.cat +ezy_6 = +ezy_7 = +ezy_8 = +ezy_9 = + +[md5s] +gm.cat = 7a29d2d0c4f7d2e03091ffa9b2bdfffb + +[catindex] +theme = 0 +old_0 = 1 +old_1 = 8 +old_2 = 2 +old_3 = 9 +old_4 = 14 +old_5 = 15 +old_6 = 19 +old_7 = 13 +new_0 = 6 +new_1 = 11 +new_2 = 10 +new_3 = 17 +new_4 = 21 +new_5 = 18 +new_6 = 5 +ezy_0 = 12 +ezy_1 = 7 +ezy_2 = 16 +ezy_3 = 3 +ezy_4 = 20 +ezy_5 = 4 + +[names] +; Names get read from the CAT file + +[origin] +default = You can find it on your Transport Tycoon Deluxe CD-ROM. diff --git a/media/baseset/orig_dos.obs b/media/baseset/orig_dos.obs new file mode 100644 index 0000000000..e095b62210 --- /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 0000000000..4e12582727 --- /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 = ORIG_EXTRA.GRF + +[md5s] +TRG1.GRF = 9311676280e5b14077a8ee41c1b42192 +TRGI.GRF = da6a6c9dcc451eec88d79211437b76a8 +TRGC.GRF = ed446637e034104c5559b32c18afe78d +TRGH.GRF = ee6616fb0e6ef6b24892c58c93d86fc9 +TRGT.GRF = fcde1d7e8a74197d72a62695884b909e +ORIG_EXTRA.GRF = + +[origin] +default = You can find it on your Transport Tycoon Deluxe CD-ROM. +ORIG_EXTRA.GRF = This file was part of your OpenTTD installation. diff --git a/media/baseset/orig_tto.obm b/media/baseset/orig_tto.obm new file mode 100644 index 0000000000..ff600d00f6 --- /dev/null +++ b/media/baseset/orig_tto.obm @@ -0,0 +1,71 @@ +; $Id$ +; +; This represents the original music as on the Transport +; Tycoon (with World Editor) for DOS CD. +; +[metadata] +name = original_tto +shortname = TTOD +version = 1 +!! description STR_BASEMUSIC_TTO_DESCRIPTION + +[files] +theme = gm-tto.cat +old_0 = gm-tto.cat +old_1 = gm-tto.cat +old_2 = gm-tto.cat +old_3 = gm-tto.cat +old_4 = gm-tto.cat +old_5 = gm-tto.cat +old_6 = gm-tto.cat +old_7 = gm-tto.cat +old_8 = +old_9 = +new_0 = gm-tto.cat +new_1 = gm-tto.cat +new_2 = gm-tto.cat +new_3 = gm-tto.cat +new_4 = gm-tto.cat +new_5 = gm-tto.cat +new_6 = gm-tto.cat +new_7 = gm-tto.cat +new_8 = +new_9 = +ezy_0 = +ezy_1 = +ezy_2 = +ezy_3 = +ezy_4 = +ezy_5 = +ezy_6 = +ezy_7 = +ezy_8 = +ezy_9 = + +[catindex] +theme = 0 +old_0 = 1 +old_1 = 6 +old_2 = 2 +old_3 = 7 +old_4 = 11 +old_5 = 12 +old_6 = 15 +old_7 = 10 +new_0 = 4 +new_1 = 5 +new_2 = 9 +new_3 = 8 +new_4 = 13 +new_5 = 16 +new_6 = 14 +new_7 = 3 + +[md5s] +gm-tto.cat = 26e85ff84b0063aa5da05dd4698fc76e + +[names] +; Names get read from the CAT file + +[origin] +default = You can find it on your Transport Tycoon CD-ROM. diff --git a/media/baseset/orig_win.obg b/media/baseset/orig_win.obg new file mode 100644 index 0000000000..393b5d3013 --- /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 = ORIG_EXTRA.GRF + +[md5s] +TRG1R.GRF = b04ce593d8c5016e07473a743d7d3358 +TRGIR.GRF = 0c2484ff6be49fc63a83be6ab5c38f32 +TRGCR.GRF = 3668f410c761a050b5e7095a2b14879b +TRGHR.GRF = 06bf2b7a31766f048baac2ebe43457b1 +TRGTR.GRF = de53650517fe661ceaa3138c6edb0eb8 +ORIG_EXTRA.GRF = + +[origin] +default = You can find it on your Transport Tycoon Deluxe CD-ROM. +ORIG_EXTRA.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 0000000000..b5d4b024ed --- /dev/null +++ b/media/baseset/orig_win.obm @@ -0,0 +1,106 @@ +; $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 + +; MIDI timecodes where the playback should attemp to start and stop short. +; This is to allow fixing undesired silences in original MIDI files. +; However not all music drivers may support this. +[timingtrim] +; Theme has two beats silence at the beginning which prevents clean looping. +GM_TT00.GM = 768:53760 +; Can't Get There From Here from the Windows version has a long silence at the end, +; followed by a solo repeat. This isn't in the original DOS version music and is likely +; unintentional from the people who converted the music from the DOS version. +; Actual song ends after measure 152. +GM_TT10.GM = 0:235008 + +[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 0000000000..e1c2c4e11d --- /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 0000000000..f15cb43ffe --- /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/baseset/translations.vbs b/media/baseset/translations.vbs new file mode 100644 index 0000000000..fffb577482 --- /dev/null +++ b/media/baseset/translations.vbs @@ -0,0 +1,123 @@ +Option Explicit + +' 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") + +Dim inputfile, outputfile, langpath, extra_grf +inputfile = WScript.Arguments(0) +outputfile = WScript.Arguments(1) +langpath = WScript.Arguments(2) + +If WScript.Arguments.Length > 3 Then + extra_grf = WScript.Arguments(3) +End If + +Function GetExtraGrfHash + Dim WSO, exe, line + + Set WSO = WScript.CreateObject("WScript.Shell") + Set exe = WSO.Exec("certutil -hashfile " & extra_grf & " MD5") + + Do Until exe.StdOut.AtEndOfStream + line = exe.StdOut.ReadLine + If Len(line) = 32 Then GetExtraGrfHash = line + Loop + + Set WSO = Nothing +End Function + +' Simple insertion sort, copied from translations.awk +Sub ISort(a) + Dim i, j, n, hold + n = UBound(a) + + For i = 1 To n + j = i + hold = a(j) + Do While a(j - 1) > hold + j = j - 1 + a(j + 1) = a(j) + + If j = 0 Then Exit Do + Loop + a(j) = hold + Next +End Sub + +Sub Lookup(ini_key, str_id, outfile) + Dim folder, file, line, p, lang, i + + ' Ensure only complete string matches + str_id = str_id & " " + + Set folder = FSO.GetFolder(langpath) + + Dim output() + ReDim output(folder.Files.Count) + + For Each file In folder.Files + If UCase(FSO.GetExtensionName(file.Name)) = "TXT" Then + Dim f + Set f = FSO.OpenTextFile(file.Path) + + Do Until f.atEndOfStream + line = f.ReadLine() + + If InStr(1, line, "##isocode ") = 1 Then + p = Split(line) + lang = p(1) + ElseIf InStr(1, line, str_id) = 1 Then + p = Split(line, ":", 2) + If lang = "en_GB" Then + output(i) = ini_key & " = " & p(1) + Else + output(i) = ini_key & "." & lang & " = " & p(1) + End If + i = i + 1 + End If + + Loop + End If + Next + + ReDim Preserve output(i - 1) + ISort output + + For Each line In output + outfile.Write line & vbCrLf + Next + +End Sub + +Dim line, p + +Dim infile +Set infile = FSO.OpenTextFile(inputfile) + +Dim outfile +Set outfile = FSO.CreateTextFile(outputfile, True) + +Do Until infile.atEndOfStream + + line = infile.ReadLine() + + If InStr(1, line, "ORIG_EXTRA.GRF ") = 1 Then + p = Split(line, "=") + If Trim(p(1)) = "" Then + outfile.Write("ORIG_EXTRA.GRF = " & GetExtraGrfHash() & vbCrLf) + Else + outfile.Write(line & vbCrLf) + End If + ElseIf InStr(1, line, "!! ") = 1 Then + p = Split(line) + Lookup p(1), p(2), outfile + Else + outfile.Write(line & vbCrLf) + End If + +Loop diff --git a/media/extra_grf/2ccmap.nfo b/media/extra_grf/2ccmap.nfo new file mode 100644 index 0000000000..0e99ff8850 --- /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 0000000000..a98fe67000 --- /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 0000000000000000000000000000000000000000..cfa41f2c70bbf45f5d79d57d4b5d1d4d6ac52a89 GIT binary patch literal 29520 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
  • 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 E0Ch~)&j0`b literal 0 HcmV?d00001 diff --git a/media/extra_grf/airports.nfo b/media/extra_grf/airports.nfo new file mode 100644 index 0000000000..45cd25de04 --- /dev/null +++ b/media/extra_grf/airports.nfo @@ -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 . +// + -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 + -1 * 0 0C "Climate specific sprites by PaulC" + -1 * 0 07 83 01 \7! 01 03 + -1 * 0 05 90 02 0D + -1 sprites/airports.png 8bpp 320 88 64 31 -31 0 normal + -1 sprites/airports.png 8bpp 400 88 64 31 -31 0 normal + -1 * 0 07 83 01 \7! 02 03 + -1 * 0 05 90 02 0D + -1 sprites/airports.png 8bpp 480 88 64 31 -31 0 normal + -1 sprites/airports.png 8bpp 560 88 64 31 -31 0 normal + -1 * 0 07 83 01 \7! 03 03 + -1 * 0 05 90 02 0D + -1 sprites/airports.png 8bpp 640 88 64 31 -31 0 normal + -1 sprites/airports.png 8bpp 720 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 0000000000000000000000000000000000000000..5fb9618bc5bf8113df7bfb7e0739c3864e441d7f GIT binary patch literal 9491 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. +// + -1 * 0 0C "Climate specific airport sprite by PaulC" + -1 * 0 07 83 01 \7! 03 02 + -1 * 0 0A 01 01 2F 08 + -1 sprites/airports.png 8bpp 20 170 42 39 -19 -21 normal diff --git a/media/extra_grf/aqueduct.nfo b/media/extra_grf/aqueduct.nfo new file mode 100644 index 0000000000..d9ba739f53 --- /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 0000000000000000000000000000000000000000..6d55f0aa469cb507f7ab419524d807e3e735ad00 GIT binary patch literal 3609 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 literal 0 HcmV?d00001 diff --git a/media/extra_grf/assemble_nfo.awk b/media/extra_grf/assemble_nfo.awk new file mode 100644 index 0000000000..cf6b425c1d --- /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 0000000000..08aa5ef9fc --- /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 0000000000000000000000000000000000000000..5c21d3602fad8d2f7c000b9b7d8aeb5e1abf644d GIT binary patch literal 5503 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 jMepvxV(~@ZFZRT!S2?%s1CcI-HD;>3*`H(tDW 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 e*P<5ut!L|03SGZWrh. +// + -1 * 0 0C "Canal graphics by George" + -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 diff --git a/media/extra_grf/canals.png b/media/extra_grf/canals.png new file mode 100644 index 0000000000000000000000000000000000000000..f9f6da6f9ffe3286b03e63e188a33b23d8a15b73 GIT binary patch literal 6236 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. +// + -1 * 0 0C "Extra canal graphics by PaulC" + +// 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/chars.nfo b/media/extra_grf/chars.nfo new file mode 100644 index 0000000000..32462f8c1c --- /dev/null +++ b/media/extra_grf/chars.nfo @@ -0,0 +1,845 @@ +// +// $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" + +// Note: Characters in range U+0020..U+00FF may only be defined in chars_orig_extra.nfo. + +// 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 0000000000000000000000000000000000000000..34a4a67c5d1193150089c129fe7b2db97df02960 GIT binary patch literal 16993 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 literal 0 HcmV?d00001 diff --git a/media/extra_grf/chars_orig_extra.nfo b/media/extra_grf/chars_orig_extra.nfo new file mode 100644 index 0000000000..7979e79450 --- /dev/null +++ b/media/extra_grf/chars_orig_extra.nfo @@ -0,0 +1,249 @@ +// +// $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 diff --git a/media/extra_grf/elrails.nfo b/media/extra_grf/elrails.nfo new file mode 100644 index 0000000000..7b8e9dace4 --- /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 0000000000000000000000000000000000000000..a5166da2cdaafa86dacd3931a6ccae5c5ef8b39e GIT binary patch literal 6033 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 literal 0 HcmV?d00001 diff --git a/media/extra_grf/fix_graphics.nfo b/media/extra_grf/fix_graphics.nfo new file mode 100644 index 0000000000..1144742230 --- /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 0000000000000000000000000000000000000000..1dc7bad825ba25e32753711c0c576b944ee2c38a GIT binary patch literal 78210 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. +// + -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 0000000000000000000000000000000000000000..2e0401ffce5ca5255c45c91e645da4e53e2649cf GIT binary patch literal 1763 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYU{K&-W?*2r>-Oe20|NtNage(c!@6@aFBuq^ z83KGlTp1Yt3kV1(C@2^h7&tgM1Ox=6q@cI-HD;>3*`H(tDW z@#oJU6B`c~pO}b*f}E0;mYx}N7OdH@kDV>^bn~0>hsdHh=y!_-HUB*l?6Y$aIug%;^Z&Fem58mJSyQh6Ej!1{aPw2?9GR zB(BU+c(Fs^&lQG0KN|l0IiSG8;2^>gA|sHaBhz4^F~!4TMU2mmoQNY0Iaj7MaF{R% zI4~##uoxt;I27=Nw1{L(k!e_=BV!_=Jof8TY3>GpB9vUnWCOjDq5;Y+@Jvj~w8X|l&1QJXnN?bHL zLM)afIP540IMa}DWlF(=6%B9pObL)-Nzo9gu+Zr7aafR&u%n|xMZ?9wB*eiXB_N*J$sZGw zKPeG^Ce-}dvEa{*6Mw$E@enD9(dj90S<#bnWJSk=6B~Y9*zy0xg+De73^5E04Gatm z7#NN)Fg##j_`|^PCxGEk4#S@ghCfRf{v2TVbBE#2ABHm>98V^&{F%e>XM@3?BPoAw z%;1oS;8DpCF{zPp>CuQ;Vo|ZjW5$h?H4kFunB;75s5#*?;X%xUFMm$F`LX5Bo0dH{ zB4(`l!tmuQ!`E*N-@Y?^|H1I%C&SNQ48MLe{Qkr6=P$$Ge+>WrGyM0F;KGcXt!FgQ3c1Ozbr|IeV{QlR2d zqTy4a6HsFi(%_LYA*E%-jW2%^8kV>u^!)$-|8%(bLIwuriJmTwAr-gY&b(cC+d#lI zTr}Z|$0esr4b>dgC-SpCa2QLiWcq!3X28Em!Hv<24zjxxFurL@oD=bAZ(UEgf>`(Q zgG?r-0xYSno&6p)Z64c%&rg05ukC-_S>;>jlus$g(|?Gc`n_yw(WO`Br~lMH__0n- zpeuYwm?zr;2G5m$Q*2bu1uQ7i`uD&0{V|5jDYCXq zPG>EO{|0M0MNMM#m|OoV`M)c}>aSCa3cLT`_;}Y!A&V{GT+9*+71Ng@3{GD2O&PfU zOy2Z2>*=R&bNkm{`M-!~QJTh6p4GkweeXKnhzQ6zziYFJ7gOMSg~N(FC-NO!BDd)2 zuUYj!dDc(&X3+R}@zb~NcM2`m9h;^)3a~gRWJoI94h+u>510GD_4aoD6LtITW%%BG zH(*$P`SH6g)i!h4svn!)xE7V{6MMb+@2k+S+dfL2dR=_CE`HwoRqanp?^f-eay{<$ zMfuP9&A&wJ?;Q=l9hO`(xuUWr?Q*1a{`|eiDs=kQ*S!Dp`CDx2!o4T9)z~Q2C)VHk zXmq(qdfNBi=f@|1&wu~)?O_wU>}CJztJbnlSj_ySLQ>(l+xM;7Y)hoy=_u43TC?>t zLm~GcedbGR4JU7W&iv_<5%+|BTQ7cNo|I|NcI3l9Kd}#!D=|1zAN@DK34XkU$;Z+RK(?q)e;ld znS8iE%j^utdZ%ieeO}Bh*T4UXdo%5a0rQ`KR*Wi4*Lb46_$DlW`T5-6!_V7o8futx z_=RPaX7U{RwZD(2NW`dv>BKe0q+6yFnU~nPf7QMHu&1b{a;njZr$1MjG`lo>Ig@tl zv1Chsd)bj7#*f+;^dIQof68-+;URY%bIbAbjD~3rOLCZ_Srz*F1t&az{!&(D;-}@3 zDOE?L`fVOFS$|fZz`_w9Af?bLYtOPo%OdG(?5(uN(-~HpIQ(e(^3Ll$$1Oo^rXzoM zW}Dvl?l=Ed{LJUU3^Gm1;`94Omp|P` z9cFUBDo#!>v9q7oFEHUZ!-Ol|6D*u%^j;@^Ef-*8>D8(}YxSx&?y=UtyU*|6+x&OZ zj}NoN|7)}?DE+rspoxKl#gTypL@^3*Fe!kN6i0)D07Ih!0~1IBN-=P-FbZ(|x?aU> Ypl7yEa#DId0|Nttr>mdKI;Vst0C>. +// + -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 0000000000000000000000000000000000000000..c05b80e91ea80fbfbc4876aef81216710d233713 GIT binary patch literal 54976 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 literal 0 HcmV?d00001 diff --git a/media/extra_grf/mono.nfo b/media/extra_grf/mono.nfo new file mode 100644 index 0000000000..a5f0fe5eaa --- /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 0000000000000000000000000000000000000000..fb52e1e75bcfe7687d82de7c8d151d60084aa2b9 GIT binary patch literal 4856 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 BYW4sC literal 0 HcmV?d00001 diff --git a/media/extra_grf/oneway.nfo b/media/extra_grf/oneway.nfo new file mode 100644 index 0000000000..74264219ec --- /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 0000000000000000000000000000000000000000..15542af8563cdcc8870d2a251d01ae0a8daf9e83 GIT binary patch literal 1222 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYU{K&-W?*2r>-Oe20|NtNage(c!@6@aFBuq^ z83KGlTp1Yt3kV1(C@2^h7&tgM1Ox=6q@cI-HD;>3*`H(tDW z@#oJU6B`c~pO}b*f}E0;mYx}N7OdH@kDV>^bn~0>hsdHh=y!_-HUB*l?6Y$aIug%;^Z&Fem58mJSyQh6Ej!1{aPw2?9GR zB(BU+c(Fs^&lQG0KN|l0IiSG8;2^>gA|sHaBhz4^F~!4TMU2mmoQNY0Iaj7MaF{R% zI4~##uoxt;I27=Nw1{L(k!e_=BV!_=Jof8TY3>GpB9vUnWCOjDq5;Y+@Jvj~w8X|l&1QJXnN?bHL zLM)afIP540IMa}DWlF(=6%B9pObL)-Nzo9gu+Zr7aafR&u%n|xMZ?9wB*eiXB_N*J$sZGw zKPeG^Ce-}dvEa{*6Mw$E@enD9(dj90S<#bnWJSk=6B~Y9*zy0xg+De73^5E04Gatm z7#NN)Fg##j_`|^PCxGEk4#S@ghCfRf{v2TVbBE#2ABHm>98V^&{F%e>XM@3?BPoAw z%;1oS;8DpCF{zPp>CuQ;Vo|ZjW5$h?H4kFunB;75s5#*?;X%xUFMm$F`LX5Bo0dH{ zB4(`l!tmuQ!`E*N-@Y?^|H1I%C&SNQ48MLe{Qkr6=P$$Ge+>WrGyM0F;KGcXt!FgQ3c1Ozbr|IeV{QlR2d zqTy4a6HsFi(%_LYA*E%-jW2%^8kV>u^!)$-|8%(bLIwuL5>FS$kcwMxXT|0nG7w<< z?j>sO=5>|Z;*rR-szqU*Qd5QU=Wh6?aNtbxwK%yO7k{1K$8g{%*Zehh&(42{sB!&w zi{YQ!j=2hDKR3oT1TwdrWW3UJ#p^;+VRyNPOygg!r0ai9Y-8H)CE)m=uX=(PW3;W@ z-R2`!5)Q$R3=ED8w>Xmc`i0nU%v7jMdHW~Rr0GC6$E45C4^%lWdnoDnfR#n^_Q5ho zu2>ew2QOKE7AjXa$*^%Xo%zhvBy+AJwSfm-e))HC=_G~4O4*;&{RPzR8{#I2 zvEC`qzk5<}No#{&9m7_I-f0fU_xWE8UiE)kL2w;Q<83abdoHW_85x!|ZLw+Vy;mGl z+{2?F?ov5%`MwU83*1UIT#M>XF)a{v`7. +// +// Sources for OpenTTD's required base graphics. +// Checks whether the correct version of OpenTTD is used before +// allowing it to be used. +// + +//@@WARNING DISABLE 60 + +// +// 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 +//@@WARNING DISABLE 101 + -1 * 0 08 08 FF FF FF FE + +// Name of the GRF + "OpenTTD's default and fallback extra 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 "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 "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 0000000000..d0fbba0e70 --- /dev/null +++ b/media/extra_grf/openttdgui.nfo @@ -0,0 +1,189 @@ +// +// $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 179 // 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 + -1 sprites/openttdgui_group_livery.png 8bpp 0 0 20 20 0 0 normal + -1 sprites/openttdgui_group_livery.png 8bpp 21 0 20 20 0 0 normal + -1 sprites/openttdgui_group_livery.png 8bpp 42 0 20 20 0 0 normal + -1 sprites/openttdgui_group_livery.png 8bpp 63 0 20 20 0 0 normal diff --git a/media/extra_grf/openttdgui.png b/media/extra_grf/openttdgui.png new file mode 100644 index 0000000000000000000000000000000000000000..900a612a87f17902771a5d7ae18b6ddcf64021c4 GIT binary patch literal 26393 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 literal 0 HcmV?d00001 diff --git a/media/extra_grf/openttdgui_group_livery.png b/media/extra_grf/openttdgui_group_livery.png new file mode 100644 index 0000000000000000000000000000000000000000..f45be670cb764012f3262295f526d2ddde0a3ae8 GIT binary patch literal 1426 zcmeAS@N?(olHy`uVBq!ia0y~yUgl#-H?mX?+&Q>Ls~v0}%L9VbqlxN+mgix)5c{P|;IL^wiZ1afp_8Z0!Xcv!56@!63Raik&V%9I8U69xeX2893?g9H|b0-lf- zk&G!a4J&kHOeAz%6l@|40y1neYJ3`|#LU=`v*k>UfQf{HhmJ*phfhgFLPt);l8zY% zR_wTQLP3JTLWaRZgC)X*C&NLaCPb$v$6-N3gpYS-{}2gCXIHM8zG82`?g6d}uiG zXU~H_0uBih0XZ586($8O0X+*!)*P5~=FXW9f7Y0oTrn~EV`B0rCF0M7nm;=h{JC-B z&zCnIA_XxzJq0c+dQy(8=y-5q!;cF){=c~J$A*C+hJm4hfnfmy!x09C2Mi2<7#RKp zF#O43_|w7gX9>ff0}OxeF#P$$aHfOf$pn@^a~S??F!*yM<OD)xBHxRJ8vLChSJoDB{&CwwM6hIVx^cd8Lt){>nLC-Q)BPA? z6d#07k~R#o&$+3xnuDur{gVClC%1Jh@_+Qv_Js1{2QwQCTR%jqF|^Og-G2M5TJp@5 z6M{L|<{2j{HaebXk-BxOxx;SFQ4Wtu&R$b5`!snUUg&D&X|ieE*}63yb{j$#rdhSE zi?VlIBx5x@bCbgjvzw0iLc_k zg?`hOJ3Jh^n2$35+nXZ)eqs5BS;`WPK}=!68A~Gij9$KC;uWdiGv(&*+23EXSv7hs zWHfG!(*AN};oir09L)EYTixX^;b~P`E!@#~*Vuwb1rzn&#?8X znUkJ;*famt?!fQAOgauFZnu8(v31eHKXH#=mU>^D>ts3M>Zh!ps2IJyYP;UtnjLrN zmYzkc_M6XkO=(vX=7(N3DZM&phAQXMX`d|w#oq}pRuVp_K1cE1cfo4k37R`nGL73= zSELyAr*|^!vv<7S%eL)R%-a5ai!EESE#mf1IG6rW=NbD$sm5)G`S. +// +// Sources for extra graphics to complement the original 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 +//@@WARNING DISABLE 101 + -1 * 0 08 08 FF "OTT" + +// Name of the GRF + "Original baseset extra graphics" 00 + +// Description of the GRF. + "License: GNU General Public License version 2" 0D + "Andrew Parkhouse: rivers" 0D + "Addi and PaulC: original graphics fixes" 0D + "OpenTTD developers: other graphics" 00 + +// +// The real data of the GRF is acquired from several subfiles. +// +#include "chars_orig_extra.nfo" +#include "shore.nfo" +#include "fix_graphics.nfo" +#include "airports_orig_extra.nfo" +#include "canals_extra.nfo" +#include "rivers/rapids.nfo" +#include "rivers/temperate.nfo" +#include "rivers/arctic.nfo" +#include "rivers/tropic.nfo" +#include "rivers/toyland.nfo" diff --git a/media/extra_grf/palette.nfo b/media/extra_grf/palette.nfo new file mode 100644 index 0000000000..4a6ae69505 --- /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 0000000000..646c9ed139 --- /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 0000000000000000000000000000000000000000..c2a6c94b44b283530c934328997b6327b0cf1cf2 GIT binary patch literal 15024 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 literal 0 HcmV?d00001 diff --git a/media/extra_grf/rivers/arctic_snowy.png b/media/extra_grf/rivers/arctic_snowy.png new file mode 100644 index 0000000000000000000000000000000000000000..5e44e7688700853ee8f0ea9186a89eae150422ea GIT binary patch literal 13796 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 literal 0 HcmV?d00001 diff --git a/media/extra_grf/rivers/rapids.nfo b/media/extra_grf/rivers/rapids.nfo new file mode 100644 index 0000000000..f66f3dc445 --- /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 0000000000000000000000000000000000000000..db25ae0e354710894f319725a16c8e2a4205e977 GIT binary patch literal 17651 zcmeAS@N?(olHy`uVBq!ia0y~yVDw^OVAkSbW?*2rJm-fC0|NtRfk$L90|U1(2s1Lw znj^u$z~!Im>>Ln~kzbNuoRMFk;OXqFP*9YgmYI{vz)*2(Zg6@?@Jlh<@Atkqd3Q8S z@y-ttTVF3sHUaJDd5$ixbUWE;6XuGR~G3L3p$wl`Wkvf19f=1xNfjNQC!s5 zytt$5)bEGYi?gro`Tp$ezpdBpp0D{lck_An0~|clJd6WP8+cYa$q7DaK7Qob!zX$U zja(`P3<4aRQxuE;Dl;^S^SM8N=An!g!!$ zqJ=j{g9w8|RiD!`1_w9BhPgA;f*BUDFeIE#PI}A`pv#b;UjOVeL&Mx3GpiXHqNgZ| zGA@|Npdg&u;lhw%&9LTtSeGk9gaLy{n)eY)h8wyJ2A<(*9t<0{GaNW4z`coqgNMN& zu%lIzfu))u;e@hs1w+eB1`)SU;Wi(&*9kn=VqmD4xyfdyilu8~G>2{>dw95>oW?m% zacvQ^M5e@94tj?wXG$71n(#mPe1?Hx!9-EP2hE@VR-EHockY~7-!{H@-B&4ux4w>{kKT<9ZN06sOqKvDUa^! z{ARYhZ_2PC%Z{;nqV9^=Wae+)>H-lZ2OfQAVED8<|KJr34(5i8=7;CY|G&5Y>%Ksh zp&`w4QXvCFoQsNH$f?ct$2k}nToyEHZE%$Sa!^9&0GrG~);kBe|0I~TIH?>t;_q_1pO-xvL*)tGukE>@aY{2-N9#D!2c_eW8OiHJ&l|!jwd*T z6BTcDFeY_HDED!Q&usmnc+i7Is9QzhWQRzglJ`VY55u6Y5QR_=*-y4bOqT62Zo4L0 zpI|U*`qQ?@-Ed0dra;>(JX@W2t}vHsaa+WFA*IA{R=?PS*%ykoNZIz7Eqs1qbq4>f zemm#m1_xe9up1xAG0;19*lDAM4(H_L(;Jo6@T@*2wIOT`^X|^C$>%qgvj{c19^f=% zDR)vxlymfm@QLud;juzNM#V(%7N#uOsh6cP#52BUu76RoOYrVgIlt)_!Y`eE>HcE+ z3+6B7JiKk9&Br^^H6&+CuuG&%mP@Rk;j>Kga<}C15Ce0=*E62aZF^skHyu3hIAY8?D{CFhlCt3y}K4R{?a9h|<> zdPV!H^cDFb_Dkv_|8}xP9`-rx@4O^%!N&Nyu{FU9^ZM$maLQ7|3FXQmdL7%6j*|R^MQTSs{i67^4jpfrn*LB?!d9V3MQ+k<+ z&rZYCnCw;4rcaAl?Xfy=wfpP6X6xQApSx_Y>+Zi-S-oBM0|S9hKW zw#_^$Y`1yNN!T1UEzGx()jxjwW1w^FVF%}>iBl7&KWv$}^P4!Ib+;(!?%I%UHp59=)y>46Xw%Ww>B=Pj^N7o&GH+k>m+FiB1e{I=$+i&u%mW`6F zE8bEhVijg}Z`Qdv@9b-jewp@CKRx2S!1)`-kGBb*);y9qH+c4C_jK{}oyE+--vE5@E z^Ls}3BID1PAJ~3k`)U8f`Sapi?>pBk|4;c}_5UKn@&;ALbmq=R$Hr);-#@Bq6!-Vp zTis6mw&~_u$DRc{9Yr1co7OfxJ-AjeAyG(Z3 zAJa>VJaaW-ZiHu!w~VEp);hDioPGEIy#3t%XznBK$JOF9^iRYVR4zPs=u7Kzv6Xs4 zI#$yhd^-FrrhIS|&{`qZqxwm>T(ys@@{sJIbS3?ZW*0kdILBzo`F--x@~xWmX5t>x zN|mF=OLd;^Y*Al1VUG{5&)wNp^TcMADdZa2TJ1G#o-}bnq0=fw-^tt3U!^}wD?7a= zwRO|Kqj}xi_2s6rpUmDoVGV1fF4s1vWiLXaG_Gs0Z%R)MPuqXC^OWVZ)$_E^zCE+~ z)a?o8bKcMY|5oUb(8EdFmbQ6^>&iwv+q)*qa+6JA;|`u`I=GcF`!#nc*VES8*LSYJjrEVvkG#J%@mJeiX*I@l?7!|J44OccyGvx%$Y?l=Eqq(q2Bhr#mm2Z`!Kq&!+R`@!q_(h4+5g zmbYKOx!%^Fepci5?&fXII~VV_*|8^e`N?xz7;j_Bit;=D+O9 zeA}+?ymD3cl5I#(|26H`?tI7P_x+puzFe2rj5oA*&ap?z1um6OUVi7i|6PvP>Q-4# z^_qw5m*vZ3(`EIuoMwHR@Hq=b+77=`)zstIVLudm0q7iPG;VE z*>rhw`ls_fbEnR&t<(E?C*k&@ZPm|{&)v`B&wsy5pyc5t*Z7k^3QVT^C{=m=86AX z^zZaKaWVb6A6H*rKX-A)#f8&9O`p6!w`S?zR|j58uD^Zk&@s7vCo7B%Gv&*j4Gs(}5i9})0ty`pCJQWl_Jrh|$*8&0GU3gfC4crD_;Z2b&kLJBe;Rx= z7!qtaN+M)BN-XAd1Z{;=LK_Z7irG>#{0fWa5hJ-5;6?ZHqyogxwq2b7%JrDi} zI3!2} z*yAzdM#`E8F>_3EHaOIr@R{%+=E0XgC*J(na_3FUo*NM})_h_3@|EH1H->ND8NUBu z`0< zKM4&>ToQWz|NnnF+vp6$UA52l*`+q+c$y^5>mujx4d zkx_k#RDV@~_TM@$8OFxr{r|PY7rhSj3h;^q!F55WAh2j^P+HWf*Wm+w5YM`6~(% zeB-^uQWJTlLRGR-c1oFg1uzDPumAf}irHJ@nRlSqGYv=84mCa1%^Uvcv-QfTY))EPbc@WC#hW&5F#7-Up8n72 zhj+}`?X7uA>tlW3l-BG2f2_UEEwjiaEG+L+qtUHhXUmsP3EX-Ls?o&P6g2 zrW;z`eHKy9{yedxXv37oP^Irj1^OoP|9N@p&>=0MB=L1;-S?d@-!|pUspcBd*Hyaw zQ#WZxC8P?mah=jK+%jLCZ(=iBXv+TmQ-r>rUm$TdTetSO?w+`iJ^_nOT$@`~7#d}N z?&Hw@{&U*BIp2RWZEj1n`ydp)-;i%gQGu|OLLZl3+x+DV-tKL9;Tl;sHE4=5d)qdN z{~4d73Ljb*|EfAAsIoin#rz}% zaHUQ{V8`CT+x`c4+s8&kEGi25w|I@vf5Ft=QwJ2YCMZ0fT~aQ6xxQ&d$Uc%Os_AZk{c&tA5khs>us)>L_{(DFQCd+%(%;S_fQeWPd=YKA}xo2_X)X+5Zl^VP3 z{@;3C_`CFef3Q09>ADBEpWKc=b+G-9X{5>FlS$>mX7z{v@!hPMxBT!nk8@YAajxz; zw(`uO_jXUEEV4Lse&q{S)=b{CVaCIh@8?<*}8G<HWtpl}f_Ia-Un6hd18@;EG z%jVpw`S^{qaFReA=VANiqPz@bvLlK ziV7CKx!>lHAe(&23?H@oPai+~Z}BSfg_-cT$t#qLKRitFiM{^t(88|{FZciDX|66c znW0<%P1g68^X}B~GY*sIh5CzSBu?5O`&~XJC0i}|Y)YWh6^XvJ zLHt%s3RU|r2~KO9%06w<^T{Wf%XuRvo%paUy;u0tO?efz$w!;_&+V~l+L(0L$vqm`Z&M)pN z^L+UCmMLSpzy|prbsx$l51%G}Hsj~#v*owfF0HYdCVWmTL)X2|dfguFRRNz%BVDcI;-)Zc z6?PC8-(Fj@V@iK3YXIk>$E;BWyOOsR$6tB&TBxz@bhlFDVi&e(_Sj!1KVDv1<0J0i z%Cy);PUpg`9od$T&#gEWc=1~EQ`bPTsRGOuh24+W^iTivQ9`$&Ymdi*onS-b0IYq%7E`Y24y{Dz|gW zr;XDtoV)){f7+*y3A~3EN^dOenP|FZU4PBeDgDQToD8a79KY@F5}NoduXjVNe8rQ{ zQ^#!!Ws|r;eLEy!Z9yd3RC4u*9^BXLI+*Yd?Mb(M!Vr zZOZSMD`}0>r}F16_?Mtru6kzCl(RazD{P8%pE}QKQ8y2$H+iKjXV>`QW=+4u(=VKz zMX@#6UYuT<-kRQ;r$fEKHJw)^xUSp3cZ#d#kDj1}-@Y3-r!wh!IVvqx=HqoM;M42-0R%yEKva{A#a*36t}bmMYv^ zB+_Gkkcqq3uRb=2OKX3yrh~n0+3lQ5N28}OWqei*<(f770@vmlD}xwT zPGx%Tufh7`))Mc$NX-W#UXDIXL?%e|eEs2*9<@~A!u? zmt$*l{iM#I2YJC~*lZ zy#1U8YxI-5a!VQh79BcuZ?VXYb%zf|E=?$R-@QttMBVPYChLJTOT|l3hg7^AOC2?D z+`nkIT7+etxNy_@&7oZ1%C`7xv;Gze^7A^#$Na$B>)^$fN)6UYD}xqnFjm}?_4{Cu zot#$v;vj+j%S6`b>NmZ$lKR&b^dV}&-)TV`S{6vDSer7`IcajlhjPV<-7lz|xQ8Xs zY|pm0j}I@cIUu*R;m2;T#^{JRm)BBD7exO%6Rg>hytLtS0N1h8-49;5X=d!Z^Ers? z0H18@pD9fTKP5f$VvM-0z9e8uQ}EK9DNH4sTY{!EEnXTE#wDg66tDXj+v zKfX&9#Fjotx^j(S#iwwtGx-{8P0sf;%C}8=Am>ZlC_? z_*AAJqDvS2{wP{AYsHipO@puJHCea1{qWadEm|GKV81}bA&@IblQndOaX8ni?YB$5 zPb+%4;aa2p-kaWRuVK*cxtnvzwApvpgUcGMXX92YtPvE_WL-Ra!kt(z$NC8FH+4%7=;vM9%6K<& z=>e1WlV@zb8oOrRY1!<%;n|uX2mPfAn=}e)+_wIn+Vs?SSI^|xSKeu=^6^h*ykR}1 zsiW@Olb0)l7}TdUsow~9ua>>Gs!xMeZD&x!S&OZoG^a9Mt~tRwVf|OWr41RLnhw)_ zG&@dd`B%GWGE{d5U9i1=vtqBaCPP`bSL0{)sZ0^UT(kaciPvoKUHTwXDK3O-!X<6i z=DswQE~5=x-c!RgGt?*V2-XxxYmC!$SaR}!_*(1bA|d5ktl4Y_E*7r(a=YXET+djE z<$e9T_sXy)y%!fsO7l9nL0RJetBhlEVO&h>HCZ?R$)DQf=%ny|+Ek|bYl9Nj)R&r+ z=r27G0}8|Y8mvN7kK3NE`j+RY>F{0H>)>YTHE!$dR*MwKsJa~EbysW*T5!W(Okacb z!L_MPzm|$TV4un~?~BeH6%%t!)~Ybg4~kwX&71ogF88&4DO{RxX>-BC^guH&$JFaq zO&>4!J@eCKEm41A((Ojo+G=)+`p8a6VRZgYWsZ#X(#b-kLD%+rD=HELD>irXB)w^e#B1 zc^#a@_@Q>`0Y2fRKCgpZO;&~s`)Y5rDDwz~3EfdxSgCuV?(3a%k3K!R!f?Vt)4;^T z!+x=d4^P9MDNRdTBsE!|l}~A^bUG2Kxu9n%)5Qazr0?|3tMRYkQieI-U1n;ro;j2B zNQ!epanm*SnJ#m>3H2dbE)asI+2$6K(4-d4nK1C zxi48HQuA7CsSX5&gR&3^gR{~9UqSzN1PRppYFcaz&Uwljtj(Hl-XVKZT}x(_^pvKm zZJgisFAxb~yvys=_&c7*;@-08)Kwxct_B?vpTbm9+UC`$5EI13z$)=BgiDNXp1{?w z+ov?0_1zUQKb)&!-$IcI%JJK`{_P18nELSU;d3801vQv!vvRZhd*s%-X&$)jb?{vK z+^5S$3LYe|rCV*6yQ<1Lh3V!(kvEk$B8wkw_F5=Xa>tWvDZ_*~^M_}>7*E$Nb@DDL>iJsowu&vKBcK3Les#=gdwec>p5-K6Q@4UF7ek~-k<5eMnvLE z)`Ug%%SB#nEL4bi?RNOo&BV2Hy$&8SOWL(eWXt1_Et*rA9RmW`=x@ z(|i$?$+|60;)mJKbsDUz{pamlCUPJr!m@tJ8^)y!U;j?tT&}^Y$d)F&;dNx%tPedw z2ke)KFg(&*dSH+2@@z0Q z$h^u(pUU*1eu}pEe@2THA`5CK8^|wRz&y)MmT|_m3D=Un9G_gc;IBS~$)PBJN|T*p zO{8W-RGbNeh)($1wXE?WTs_6w+zSjQH(sa>)r^RVV@Y2dp2@?|nPU{pC6>Bi`J~kO zvx6Ao)_(Tdw|DD;bAFl?dO8=RzQ-1K87u!Ah_4$TTAXic#*S^xJLDL{`^^{Ez7_)TB z(kb<|n%zMLd*;1MTiP(^cfJN|Th0UNDNSX-I`u*$YhH_oF>OO_( z%g4Dv3e%@D`K}YWu`?*aLy4U&`uOAJ`>U2Fl+5Az&+WzNd%k3q#;++}jCWRwcnB?Z z5Yl2jEIfIpChH$|Js(EIhHynZkXx#-B#6stvB-?ZAcycNO;d#@A9$g!$tpAR zz`eyHEh=7&$9D!bs840Oa8-D+DEGWjt`&h?A`@$@mNNYI-KFh+F05j`NJz@>!zqQH znjijc2>S5th)Td0@u^I1@~=a@8U>5i1{v(~yle4adg+6c`|_85Zd8??JvGR|C)Sq`KiHLF+FI(o*K2SK{C(ljs0A! zW(RDoE%_<9G~xA;lr%5K^BNP??2Sw($8Pu6ba;PX&1Qwj8oy&=^KEKfH6N&WIfe*l zCL3jb(_*cgAaL^j5|K6bmA`&_9SrV?o$E6%l&dG!lOuczQ*)k8q|I898J_N|nI3If z9I8Hr$+>&-NntNWgL^APW}NIi$?eq`xUA5f`Ssfkix)m%U7BDp(`JRp7tYMh&u5+X zVpI*{y6{!@tU^`-XW5;L6K>8A=X&J1^ug2#e|9{7wB$L{FPkY$i}$_eP~f5d9HMQrzY!>gt_ES1(8&&)M%P)ZPu_w z9tHvKa=I7NmWb@(X$aG7xEMWmYS4kU7}@3(CqpzPBpBufZOAVB)EIPb3e$(ub6y9J zFf3RkGN&VIN>fW}IdmV2$5{ z(hvmqbs#;ReN$XDCH|gLHrHl-c*Jkx{1C2LHQO~=n|(J#YOy*lUKYf4tEOC&b+Ye< z=~J1!mWYHj9j@`5(v%ncG}r6kn+GRLmohZZ3FZ>`)vW3-^?dgVkrV1um~K|hxN$Ft zuUsem)W0=B4Ewm#@9=A}db9hl(`3DyxVF~oV77GO(WH7e%?mq&Hf-?SelpKroAqv@ zuEjc$gzcW4+E`6}I*J8$2?wTH5gQs$j;2iv{aMOxm}8(_npZ+jrOE*&@^YYVx#M z--^G#>&19O#H(?S6_ZLZSAw%<#;4nNy&SLDdL4WxUE`@)!S>a2D${~~4c1eQqPtE$ zsa~3JJFwx2*Fj|Y^rfpKZVUmq<4xgf3s>%PZ4-Zg#y0+AlI?gCfM8Kov$4xYE3#UK~V6{a@XeQFb1 zWkevCLSvA@Je^0POBcN5NV|P^<-QdnI;R{2LYVrh-eoRr5Y}YPb$59EO{c!jSu5VC7sawp1bY%KZSY1sbfJpKOy%Ts41OLhZsKA*xA zJf&%o$e*uXjVeK0YCr1&G#gaB8s~&^naSP%IX{GJ7q4IXl%|W1_1%BIuwNsO6lZ&1PuZ?DFf5Uvd9;Oxqq`!oQ>;;Ome zquSkq?w|+X`xd9a|HZeoK}eI;jfbs1PLshri0cdA(g&T6leAgcZu@J_3+6iGqsid5 zZoLNUy8BDI&sG#oy04KDA~?A_=z_1<+WiYe1fpNFvoUnA@Fb-MYC3Fo)?`?kH+h{D zYfEGu!~Cg12kIBG%$hgDW|fGczPDn9M0nYXAL~Cd?D) zT*i4>ll5U!P(s-b>(F5Eu;9n9M^1GH30TSnaV@hIU%2kMQGnJ`hsj#3i=UpK9(3WH z!uNG1U(HwUTqbfxD9F~gqr_3ufbrPmqupMNxk_sfCq4~ay1;6+$b(%$4PR9hRf4$; zT7wS!o@URl%~~=!$iRz3PZ=~!VEv6-F^FmDgIp))eX>8&7K*%i3$6v$h~%iPxv=$5 zce%XI(^Wwm5*ca&H5+0%PhNM`yrJ_{x#{cfDNNB*n#`Bh*vz@VRD?y(>)`I7ec@cU zzAuEKQlfO?axe_oB6UI(v(OKy15 z2Dh3(ZKhA_^-}}6-1dJ8*{;c&_V)R!;y}&vr3{u2-g+_q3!lO?J4SOs-fX>s2@D}q znkFxGS@k+ic+JPpxw~97Z^WLO806rp>9I`Yf~}WhJ&%?8(u4``t2FPjPi>mf7?f~L zzOp)0v*4c@xbS_pQbdFOp?mL@q>V26P50dzVfQ zGPuW5?WDOP=kKeG85@Hb42vFgdpT}hDpH`dbivz4b+G8X?{bj?l}jJIyr;$bBXjA2d=1uY+wV()46F?+<1|+kxVvwjAI_!5 z?7iiEbsp1Fhjp5)d5ae(>UlBl_-?yhgH?OIxgST&exXCJnBIm@W%|Rp^uPppl`YcT zTjX_~K3@1K$J*)Y0V7LoR_;Ehts5PF^DbrZwA7N$&OPVV_(;!v;oqdcr#L&iURf2S zu%7>Vgu%d4ll3xdz=;UW1uv8ypVwfWvNVX{t_=@U*ppdLT_>*&x}eu^>&#Rpg-_jV z4t8FRXQnWn3Dz_SdA?5M#d;0a2Y2o;obb{N_$RpZfbUeMGXa_t<(J+Uv#O0N;uawvx8zw zA0%j&7SDcnf0f9L*;AV)tPL_aJ>5amp?-Og!OdmfXVoH9>O(XeUKScztP#n{SKhZy zgyCn2SL425uA1GP*LFSjYLu0|W>h`3sg~c`dbx-X-{i=)6t9DCe4ft=O1K-i)WLVX zNJoprgrhxtdv*W6T%3Nz&1LtV-W~fr*K4s}tB=rRs1DH#Xj~cOpq24AZ>fUT|G>pT z=gnUB`Pak+ajojtW@YQwVwKVC3`+R>B`|6F)Fz7%u9)>A8SA_n*+Sn~N16MvTCEXz z(G-+0HInttT<^^HbKBBn9D7X_vgCB ziWTWKdJAuQeJvskC?;!M-h>QI~=;>L%5E~ zE{u;e3Anz#@7ezKA|GNj89rEQvaWyX+H&(#(mAijqJ-JYg8~+Qe*E<4o~cYHgETYt z>G|45#Z5UgmFZ-pW`irUg8NbiaiO&3B5NcVTs193w#LWlcpdz@Vol;n1`V%+GgsWw zWKHM}DllDDAi{WLmoY<8DAz2{yl-BN5wB;a{?7S(-RozCN#CJ-4b~@FiK#kX2cNEZ z@j0Api3V%tC)*?)uY=oh7tBwsmojt*P4Lh(*rvgHa!OOw;;uqTZPpLbUX0fywOJc7 z{s((G*3J)N2)WKVh3PNv(uN={*0dsnwpr~q^TW6b>SnwV_Bxm?yvA~ch>pxPt3@IQ zRs|)@ShIhDh{W!K89JRo4YR@WACFIAy8I@h?PB8E?Ou#qZ+9GAug%J^&2GI&$TeL# zHShHzGoJlPE-$uSX#KY}Z+Q^IlaPi3eN&sR?_6%{<@ogWLjJQ;nZ9f-?^2)2l>B;O z(1%myo|+&2w#)pQJz<$wf_%x$!V@?OrcN9xiGF3*`a1j zg92Qq^a{_zvI`A zAcHrN8B6WfitMTUWa8$tLS(`IU`>Xk+FbYOioM^x7*&F}Hq7jiH0g6bazd)%f?5dI zn*M)wOBZYspVFkZu=?wrS6x9DCKo=t`ViENliI2Dyf~06!SJDjrov<8$E-^i)UMn7 zR=qoYYSYoawz@5UGKDl*C%I_O_!9HMZb5jXw^!prkgEjm{QC5~aOs1YVVW~^E;!Bg z(A;3QHfY1XKb3Ks4)Z-UD<&HlFKx)I{Q3E|*FmGpR?!Rot_or>3FH!+c#UUDlR4+t z(_W5Cb8J@!?BCO|@O6eWvx4zbhv||x^|e{2mR^498nSLv2v^3{z!OfI3_VTWYz!&O zMHqh7Ol3+EUAmHyp)pzXVCpiFhNV^OL?lkQYC0UN>RGUjjp5gsDNN2Och3YGT>G6f zg()J0Yt@6IU@o4C^EFwI{hBkSsmfEc;HM_*lUFl?8bG7W3`QYbJ^A$)e+n*D&^lg! z(dyezP1b3V5qI)6SbG^0)@&_Z=f!9e>~SJiGlPf0;F{>t2T@n5R$FBp_{JEt^loxj>Ri0eW6l%{VF++6L#mmWx2Cvs)7?}i69 z+QIX@4j!Ao-~2xN)TUG31}XX)tX1=aKB#;BFkQ;7-&Y%zbHwHCC&rayqVD0XoQo9;d_pLKo zP{7U`1^8jhn%1LLK8b8!68Z=2~It6LvLo zYSYr$8!{ho&rbL*7umJUa?REG_H*SX)O}w*IlA_Sr0MLE=2YHqQ-T_VoC6Nrp3-#D zcgGISvi(5^vb3fxWHhi=*z2zOfORRu?fo@XljQ=rI!xKNy_~{SG~0jPz9k|n7JW@- zPAHp`vp&e6eoBPY(gSM2Ts>cJpD&fOUG;iJkb(3z-YHC0YekNnNT14NE%9r?Iu)Ch zA`Cz4jM(x%p1gd03e)aI;NjNLLz+tul<;@PhH~wi`!{?l(}!&Td3NhX8vZS;bWct! zbf3!fV!L4e98cc6na zu#%~`*9 zl}ZR#n(W$@oJ#|_EcVHMs+PAXQn2^t@aFuRy3`@Ex1}TK^DDhS!d?f9+^yG%?D*`} z_&91Rr7#_*9wsZEGL{m zL(NkZPMKLRUEuwqD1=LFx_CRAgP)hlkQK;vYU{^qQ-r1j!TT6zw{PbuNK*3X;>MhSrL`4yYp6cYOCr}g_vNj z3w!f|9&dT~kMrWS*Q{ZkY6TrhI|8|Kw3a4(^jW^~`c$T#d28cM7^d-M?+xZ^*fxbJ z<^D5w(e0~5diWfqUr&i#9X+KrcrIw<~2P;;%ObUFf^^o#$tBWNlH|UU$ukvd1AMrSmWF%(!+ShV#b0=W^j( zYvlcp@w96sJWsds*JgcUK85M#ew(DlD>VGnCvWiAOvpL5a@D-o;paas(#c_Jn&fgc z@z86pMvo4aSw5N@?B)g;%=bBTXz~xS`18AVu1U_>yH;dIw-@95aIR^0q*h$kWc_^d ziR01*{v5xjFqOw?c6`pfTemdf-L(U&l`m{qJTu#i(KoGY_tYjk#i;$q1Aoj4GI+@e}0H{it(EPFkRmgMaga6e_h@1Ew^o{Ok()a1?KMZjs2HWg;2Bf;MS{JNz|^ zU9vw;bAt6$rWLn+HyjhV>Z)n6UPR*eEtc;1aIQo5SBmV=*I@lq?8UfVgY`w+?UIL+ zy&CT>7xBpRYFwkm`e6TJk&q`xF5LBEJo715JN0kn(gSe)RKe|9$7?Ug)_=2t z7Mzi}(Yw#ZPlNS9-h>UO%lm^8+GZzwd|+X4Z=s0E?2_s8y=xsbSIpUDE=v7n}s4RbG;Z7_Bw06*e3XRKhv*&CvRF$X?nKzp2rLq zO%Cy?Onup2j#EwutTvEZzKhw5aRV=#YLUV1pW??>K7O3{xW(Z0&h#lwA5(aQHCUy# z@h~JD)-sY>{w|0s;_zh8MM4Y=H@=>HV!c!$N8M(t^Q_tDHCQK~lvq3OrOi^29pUaP7P+~t^4DgS zaeaF7iSD(}C!a(wZ2%Sj85cYg0_S{-Y1Ug9B(P4KHSLmMPZZy?O+gH67HyUHRV#m* zJWq=?<$9H#+kFkz8ZXU?drL*W$TqUc@}ARVohst65t zy$)(8E;Wc?XnixKDcqeQHPMj!^!)fxu3IfFXOhCI^img!@JtiebYGeHPIh3bS1_ zHxw^DFu{e7XPe(*kqPVhHCZpW&*kJ+3+9@@y!e8`{I8xf=dn=az=tDGYG%L7T*_d%;n16gFNI4RmU$g~ zapbw;(gU5cGHSwnFJ7t5FErO+m05jL?S`|LW5yJwr~ocCnSqQNTq%TM#d zYA?qJWeJ&VUXF8PG#T9N>q4f>$*|vBBC=rbGLaeA8DC^NRmW*IlrCM6bnxQhT|pYG z1(BK^-Cm3`p*eUNSY$!yl0bI`nG%zNLoz+N z*-h0`n38x8X#1b@TP|WVS(9~kx)r|$Yu;%Fg9AE>Nx{Mg?s_rm+FDvK3`&q-UF7up z)AXrKeyc@vN=zKyn<`!V8o0FK*<{Z!v-GJ=nTNU-HOceT=xeaD#X2ob*t&RP_nH^} zTC9_eS3X-2l(1-~T8oujynV4_u9D|lKMmH+#w)+A2ufHJ>-$2@ zR$NbmwZu_##fe{c*%)?S_Hz7P>iKR;P=MgAUA`RetMuwTH4nscth$uC)M33Q>oL94 zRtE2Pe*5fou%_~&j`E5~4b}kvRM{xM8&}2bB2JYqby)W9oU!`S1jC0pjb_424}1XS zl-WTCwELQ#EfINfg~4IXn$sSdGt|#`Ybx{!&F}VNw0b^G&hO*HAiHZatVWMnZ>^tq z+px#upi6h2qo%==D_Le<2X!81G;TZPq-ikig1#o};q6xJOA{;?Y8|(k!gP2EV{IT; zkjv4$O2HKxtl^6{u{~_qroqa&XqAERRaZ?9!LRI7nNG!PPFN%o(+6)Lo?j%gr1Mut zyT3w>S$rVZzKW@kCSuSu)cOm&DBy$VQij8w&u`YaX=^>Wgw)nKkCeoGhJTxMoir2p)@+&aepQgcj|sE=G$Zb^RC{U8unYRu5_I6y0naH+ zVPWew*!zgJ#QzM^U@e*)bYWiW&UGRlR!bLH`lQ8sF>06pyrjjNaOacS4P!4ykEJ3# z<}c&IxDN15X=>14+7PV8s<5?dLxP%DL}N*TGXW z{k~|ONjkC5?BF5Ar3-@AiSaPlt`P|kKBuF}nl|tMmY{|=pcSPPg9I24n7_AF3*u7H zvkNL~4@!vH>?z*n#dz)c6sDP4tOd^CvIZ*$H)p>#>x*gUN~FZZ7G3so%w{;ywfpiP@%?VE ztK0sZUB3ROgyeKDO@>s}aD7#ug(4vV?$;Q;rY=3Oeuwqjgs&@tF5F#WQm6MdbSc9h zuS48kj^>eDN_iH&(brvlF6R@?k5u?JL zv(-gGTn&3>tDkYu3p<6RwUCJq|Gd;*T4Qr1;(RolL!KAot(vJ# z3GAo44HE*n^jt!Fn@+Pi1akGcr9Pg{)38WnPUk8kbI|0H(JOu}*6Qo&_VVzl(-2WT zFUMIcTs1YWABzsgw%KP|(7(4!b-WI$Ph~nAr1{~itQTW@zXofOX_nVghU|6u0bE~{ zy$+tc9BMsNs~tfN z;ZvGU<>f2etrl6ZX=Cxy2D_CaH}<<}F1XJ4LQT;iE|}}jt7|jFU zy%;6T@44;y5tFrJfe4RqllNi~9<^?db(WV;YE{K(-Y{Wsdwk`)SL4^_+#~P(Yo09> z*)rL6!;kfE^A9;c-p0H1K`Mic>~cLVR_UMj`+~0vhs|))BSQ0qS~vStrqA1yZA67NSx}MtsTngMvA6(t+^Y>oh zk3~TN`y=DdcxWE@&Kdbq+UsDH`-yPP6({smOp4vin3o>d@Sk;Qf^K4%7bD+PrgK4> z5^5$hHCeAFFubjE)XWfiq@q|8ugOqS`aPB9tG@4&kG. +// + -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 0000000000000000000000000000000000000000..61ff224301bda30cbbb2f9e78dbd82a2d6c67715 GIT binary patch literal 16127 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 T_q@fxz`)??>gTe~DWM4faPCh- literal 0 HcmV?d00001 diff --git a/media/extra_grf/rivers/toyland.nfo b/media/extra_grf/rivers/toyland.nfo new file mode 100644 index 0000000000..ca65ce1e3b --- /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 0000000000000000000000000000000000000000..61ff224301bda30cbbb2f9e78dbd82a2d6c67715 GIT binary patch literal 16127 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 T_q@fxz`)??>gTe~DWM4faPCh- literal 0 HcmV?d00001 diff --git a/media/extra_grf/rivers/tropic.nfo b/media/extra_grf/rivers/tropic.nfo new file mode 100644 index 0000000000..b1fa4cf3cf --- /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 0000000000000000000000000000000000000000..868468637cbc5b5a8a68bbddcdaac0db22abdbcb GIT binary patch literal 15582 zcmeAS@N?(olHy`uVBq!ia0y~yV4MKL9Lx+14BHcr{bOKY;4JWnEM{Qf76xHPhFNnY z7#O(xGo76S0y6ST@{2R_3luz^ofQg-^3yVNQW+R3Zp{r&4+(xLX8Zl#7bowIhAH0p zL82TAK~CKbA`{iL6gdUFIusY)6b(Em=<3QMePTfeb6;OWk7%F{PZ!q>_9u#q`kEJa zbe;PBuzGR!wLRaTo&C4vrO7zB2- zYBI1?GbEf)R<2-ZnaLpH_9@)vqxL$1=UNO56*D*4>{PLIZH(s7Eo2W5*OSvY=P9l& zVwT91ILkrrP~}WXqec_{2cOR{Ff5oTD)^xJ^WTbdeCy7gGwa*N7q9zjKihw$q@>6H zo}OP_;K0D}u%zzdKOOzeQVrH@4Y~goslH>$h~r*R`n@}C6Tib&h6OKgg?}ypg^laN z2|I7zeEQ_c4X-0k(TS(RYyYJmia!wkH|J-a&7bdIAMAUi(r6Uh=+5%v!J#u>e3r_b zpTyacbmv*W`=9OH|NqEdRyyLDv@=3W0l{%d!X&zO*^grd%eVyOT zcK1ygHe}f`R!`Jj5u42X&0Ad{qU6A%?+gr|cIO|wqQSx3kkS0`eEI+P_J7?Ms4_I9 zc}^;1V2E>3(F-}X+5R{O1B1(gMy(Bw(q9fr=p0~^ImmkFAorgHvlb_nBZr&>oVZdN zWQr0r*EBh4w4L1`tCgUC#X;8OKww7OLL5dwus5HJ;rUKE1* zsP1q+Vy+_8>1?FFa{`m+#w8(_gf6*V$_r9{sk3sniHDT(yAJiV8$T{QKwREBuQ_ssP#N_Gj}ohs)y{X+Pq(=Xj$On<@r zrJRSiO|>Jt-800JM?qt>5%@Faly6g+(M0mAFt%RGHrF}s<{ELgQbJhS6Z)V zUzNThKg51XUF6?Rw#dUihy9(G1TNSZ|9HQG4YTEQ^5vx5`2d;L1z1M8r+vRhY?RDK9`MZ(N@wk_IjJkVz|2fvV&x3CU-(AkN zT+G+j>gzhaRoP3W7w&c`-=DYq-Hdtr;u_}p$)yfkrY;`E0t6L(&;S$x&4*Nwj?^H|JdmB+cq za*r)mV^dR9^Y(q^`)*c{@6KhK%dCB@eU6_!b9T|$Ycow}+ZtXsdOrL4?CZ1dZ%>G- zh|<}%V%v^X&rMIFmPNkXwkNMO$})0kL}*m(X1BF-*Q#FIy>|CLUbY`52K%iUI+n4Tn_zWwOB!|x{Vom{)Cw)d|sJ8%0vLuOWc`WZYp-wEzO;PR_r&+&cHiuZ=0CQ3Y-4`U z=w4*}8S?|%Pi#N!e>i_$eCvJZdgcEq|EvCAWLVyy%9zgF+3469&Gh?6RgL2QK6|U% zsoyr;eCyb=V5g&~V}H}yrl$wjDrTH`Ghwab_vbUtO+1&$*BVgw;@SoF#Ak`!hwFIM zTiaX1+wA)aIwGVl8csJYzj(*F_`b_8muW8dW~UqaTdvpjGS#wMrI%%M%Y2u~F8gD8 zX_05HM$C=y%<-17)YDpLmY1{d{-3v>+aJw+#QnHhe1`ss*n-N1=MH^oT`sm#Pe{jV znuAY=pT(39jsjXM#ClXe374z(aaA6YJ(RAbf6?q>#|`HgEjhnW9$LOtlip0+V_KEo?ci`qR&9+}_>1&3WhI{Wd%Hq%J>s?yR+a$dZsRA-_V*-d(!8HSzk7yo>LotM_~} zd2{u4^q%j3?N08y9m*K$do}H9>Tl2Ao4?zy>sNV&kJ^2y8ZocF)W@mk#~>#1Jz zko~fJnQXeOewNd$PqW-+2haK)ofN&x|BT(mYp?EA{c*o7&p*e+CbH7&bI8feTQ8d~ zPfq`IzGv>#xwUnAKkp>mUbLWV>vJ)mc9eYDbo;4r z_>S;d>#gE*UzNPF`8WBp|MA^(cF$V3GbVfIyQ;lgtJA)}l%8jP?(Ubpl^@0aU%NWb z()RA&&sF)~kADApU+ivOk^0|rr+42hSAVy5kN=+dFAi@VZ#v&?ziJ=-@6L_)cj~ha zlrQ*v@s9g+9z(&bYX6`lsoW_vh9u{rl>`YsvMuj~zNDx9?bou-|VFmftCt zeZTlVzyFgOg?f$u89z6E4Zg7a_hiY*lmD|Y&-nZ&*;w~B0|SFXvPY0F14ET614BbI z1H;e%3=9n~85l|p7#Ln9FfdrnU|pA>)8je&ugA;2fZm4V^EfPjF4f`Wm8frEoX zKtMoBN=ivdNlQ!1lqpkItXQ#Q$Bq*xPTaV06tNS z!I}*_j-0u0$3Tb0!Gd6>5@92f5uj6(;W48nX2*hx zD|@DVxwFB6fhB@Ppg=&OL&0Q$h0mUloHH3UcUmUAnX}~2o&$d_F#LI8^XE^4j|M}6 z4M$0YOh<{uoQ{AEb8?Ps>2Q%?NYG(vaN(GfAh4rC;>sL_7dr(0Tw(b0qv6k=0}3n* z4k8>OG6Fd|G7T0QQ#>qI#Q5yUi8#`bb7e{chY5p#1A{^Ui$Ma5Ljg}ni%7;4nT8cQ zGA0r_E($gg1_2p188to)Q(|Up$k}qHM!-Zu!9&L)!NaE{BB3LvVoAr011omiIiVoI zU?Iccp}`Vi!js`3Q4^xmljE?UA;L#PAi+eU#6_bc#9~Q;!;XT0GYtt>rW8C_(eP%^ zlmHo)6b+FI3ymHhhXpAKJ32a4G+Yc!LL3}Y0s=}>QaV~%maJKG;L4Q;8X^S_Iujxs z)@1k`sfc*clksOk$Dchb{xC@7FsQUJm@HuM*uju+MWW)4#e^3TD?T(F`LpN29|4C1 ziGUo9gbI^_mVllGC2J1MIdkXChd*mfOs<%i{4p{4lM?Y~Ld~BY3;x_V@#o7M50Qcx zot^@h6+J0OR&+c#vEj#s9sgfk_+!Js5W~RGz`(G8f#C=P!vh9}KMV|i0vP_}F#PFY z__KuJ&jE%%cNqTsVK~#l@nizapE(SFHW>UllJe)q3=WA19+eCclNuS99*vkK78QFu zX52_w^B`u9NzMj`niD<~9>hHO^5?{xA6xFcY1wllV#b;;3}3!7eEr7o?K{Kw9}GW! zGW`6-@as3j?>`KG{xbai$MEkz!+#$MjvO6{2_7aJazZXms{3QZ@F#@fPX@!E8iqep z82+qb_;ZB8fq~&a1A~D9gM$M@Kmf!4{|pK)1u7mT8a@>|0W}684IU{IQd(Br`0^*A zVTnsZ&;S4bPltOiWMI(y>*?YcQgQ3e-1B)dJ2yRh`A)9v>$ddCE{8U6_#$wOk)!6G z%-!WLjvkCWae_m>^h-N~d2&p{^042*KH9H z5nE07K> zziiv@UXge2p1nKJ$M)yG+0u!e3g7eD{8qh@X??rx%iml4OJ>cKx?Ad$?ic07Wpa;yI1rpSiDLHSsyp%-#YUCM&`Hl@>wf)OD&9F zXV7ZDWlQ|O*W2^&X!p&vezz!k_Ce*vZ{4mzx?s zLy|xK+Q#-BJ9qY<|DG&e^#9+k%U9HLE}Sdw=Q(rt?%dlyX8TFJ5n$S|_z!#U`5O~9 zo}QG)HdivjPn)N}+?=`J_kP)ze_3y()lUU4zRVYY?X9%mZu8CW*teA3i+}$2v>szd{Pkz(CCZyt+jy6k?Od{_V&8c&PW~};n|8c{?pP%BF|Gi(cXphy(62EiX%x78O z&Y`-d*@rVts(1bQeEYcH@7>um=azDu<(oAp#yufV_9I7J@3S%k<9oI1{ukM3{%CV> z3Mel(o^|ot+4nw`D`raHm3#hcx#*v#Z|(Wom%G1_Pg?pyxq0yI`tIeYR`&%< z->Q3Gk;L(9(YMDsALL~`IG)vAk~Vypwc)ws%jetu&u#yIn3=Qj0cZY^jjJF2ynN&N z*8jIXAFOBauz1;PQDRzi)9L-6Z~SX7uVxWq$~h;!@qN~hqVN-yZ~y1{Z~gDpaHd+h zES6WlSj_J3zx;HDdQ%6d8QeOOARIpzETrFnd(zjLr!g&{D+p`8Tg_v@FkF{;9xrX_tT#$08=t){mba?b!G1@bY&x^VEij+_*6h~ohgRnqPHHu*NQ>NO%QlNWH0^C0qwv?yrENS-$M>(_+;K{w zf8*Zf6Mh0&9Ev58txSfyZP-55|ChJh6TZu%Eh9{JpTvm?r4no$Da-%z%invw`$}Yw zVcxabU!QR|u2`WKaKc}_U(|&~fWt*0^81wH^73+ZHMi4~*aK&>71+^mtvCW@68=6#ebZgV9L2^p5a^B>Mq7#*1Ah29xLTt`|QxB zGb_<8F6Q5k>K)75JI-3^i5Zr1D(&YE;Y$|fl7+c>^Zw%UTs-*Xu;J9yY!A) ze6RhqfT?3)LgAsdJ(6ubYbsyN+ig(uM$5`Ph0(~t{vwsze|I%88SmR$BRjE3pY>DPj&~;9>&~BG`S9kO`~68D<^MeXoXr_qBRS!< z;%kLa)%xZL|Em{06aM`9_Vvi5eJmbz#xdT@t>(=1efIMJ`&pxOYpDq<6|+x7|Npd| zQOJp7zEg(7EO-%sRn}$OF>|gEn zQ)@ix&7LUAu1?xr%O7U(v+UF71x9BqOr0x?-yD~Dq7#{8f4%yFW5}Ux2Qw8GHQjj` z&QK)X?%4Kl!=4HM|7bZRG`-mtohV(Ied4lI@#2}DVlRu#1@&x$!Xy=*9DSNH$tSR} z>@vI1p#t8UowGR)e`Pr6=kV%CAxofR+ZhH)1BU|nDZiN%w!gM0VNN)_Av`YA`u$7p zh65s>c1L#Yc3^3k_3DctU&yQtO3o~cf*p()qyu^{M|!iTa2$JaeDSZtvmFyYedsQp zeo@nf14{i?#_3$U?{Tf=)3si)1*6Z6xTdn6dXD^@rLetBfCE$lRh^j2#8DU z-XZ+bf@f9I21RF=ep53B(M19Z*>-%}`LraG|EIE@FmUVY=dxP$KTX1=!TsxVo{4*A z^Tx4OKX=~c=yIfYzwg%xv*X)d>qwlBNI4Skal*ff0(GYi+n z_+F2~&A|`t>m)^(p0(^X|GKa}MO4ArRZ-Z?g(cw1Tk|BYVTXF|P{*^EG zILFYW!WXhcg1>2V{yhx^E4d|BK`S&SxNFVzlS)0y6c`fnxNuXgD2EYi!qLK4KX&&Y zHl1fBKPj}Q{!Pu}^7`1Anq4zYUp;)L#jkYZ+iA!7yid%^R2U9goV4=ES}E!!c;@S* z<&6g>gtBO^GjD&p-%-uz+x;thBm0?FS^A%!bj)+wrgw9Tt19+SR6N8b%+c5XrzJPz zxu$|5hyMKOJ^!C&U05S}LgcR7XFKK-R!t0F62H|%)SWO8mH2O%={=8$N%}a?lB3Ud z{B=AYJl|-#SIr3voh_ z|Cry}!{=TedHhLoO_XBZ6Z@Yw3KH#e=ZF>7UinvGo04+M>{ngX!%UCOuRD&vZ||zg zN$wG!{$5Y7t=zJ^&R#+BPRz*(TbY?P1X`9ZJ)!{qpdmPdC~)_NNJ z|7XZQ%gC+W<QtvKaGq zKK{qZSR!$5izU-S#)8|Po9y{n)bbpn-pDVhb9Hd~@l!3H-}1bLO5d;J6I$Jm-}2wO ze&(_XyNn;tVrDXqJaBC5aqV-re}86z(nF6FSl z&l5RuAzQ+#KUEj6uF*28nP^;8lDXo-xA5fM*~Nhu_57Buscdy{+Og}D^YW}puY<2| z-$*@Mp%i*{<+pa5s`IOSz6wONzMk-C*VDTDa|?MbeKmiW=~)RMyi!p5ukG4|&;>I# zDK1OfALd(ldD6%CHz&=uS^A*#ir<16cYoS$|NA(0=~~n9zjK?mL~Kv_;~y$po@M;0 z{v1!Ze(;SG%%O=hUd!{I*mp>vah29#fqk3;3ztWCZ8>!3A>WmUv*%cF7qB~) zeEz$b@#flJ5BD~|voQ90y7N=w?SJ$1H!@mYb++5{f4lgc>4(2`->#Q8pIvtN+)lUe z%=hXyJ8!!E?SB5PsqX(>_eF6iw(zfi9a7T$HWyUF{_l-dkE{N5x_IY$^Y`~3SFW4< zJZ(Ysf5!jc4G!NuZ~mrx`la=2?6(=5w)dMouljyuYU)dFZm;?uJHJQ&^||_f$-BBE zS$j85I(fro;F<;Le3hMj1Ek^Hny7yKq-X+VwFa6SbE_DB+Ed7YSyswV-!e6Zo*H^dmo>_gp zsa?Y(EM4<-do!QXq%fVWq4!_@w)6jXShDF$t)pY&+wWh)8dPu24q0utFd!^_L$BYUynwX@Auz&*W;If7Weei?!EtmJSVLFB;d2>KU@4=52N>Y{S{`0 z-bmXUsh`wis5&X^!#i8MgzbM%9b(d(p1+^PBXMg`#DRIOOU*ay?fw7Z;ltY1K`;My zwH^)pHT8S-#rE37#FuyXn9qNsICbfPz=%28F>!G<_n4EG#&6WOo%`42ueRr#`8=vy z>neAC{yzW5>&wgi=iC2XS|96obHat#@Qw497Mz>rqm^?;O*(nHj_Ts?OUs@5b2`GO zU40p6bhFO%eYnQb4PUgUg?hzql6ai-S>k`*)ioP7RKz>1Z$I_&&cvkKC_ za=zU;?q#?N_uB6#e?4Ef=ANDYHuIV{tD@s?h`&A`c*Bgf%qKSK)$c=0<>m8l@)sVy z;r-7-*dw3cP3&5E?Dd(EJ-2s@mT8Gho7Z~uPSyMkcNHtX&STBX+x)7?`6YMYwDzx_ zA3kl4+p{_A@Ap}$y|Z8ZcVAVR-iLV}?FkZdk zY?W}b&q`(Oz2zeI4Tk1#-$oi_-}~O1(|_pROWWXG``Oa|Dz~3HyHDIU z3;!q`bBW5=$t!I-+F9z6lz32O(p|;2r5857`hDf-ju|^OUY0U&K75tF@>=!7M%|mC zGs4%0r6taZl9=^9qVc%Lx8611HJARCc8k-VAaH4GXmb3oP1cWZ%{Tq2DX~2KRaosC zmD9m)wz+4&XMg-YuPk@Tx=DLCA9x*p`sqK7xb4i>D$PCNc(OyfHJx99b0CeFrt>o-_)<~htOc~-l}D=0D|;^)=ImJ9Ed zGab$ql>aYjj*9&CsP^wG2PcW^wc0woJ*a31cQw9}C>Tnq{K!U$(L5w(E2C^!h~${FX)^TFJci z{Hed^s%D&jxm<6i^=X%7%XjbIz1w=-wAI!3w=U~+IrUxoblly!c7K2VEnZ$^w(M_4 z&E%|B_MP|o|JnVJt>#*0;g`;2FYRF-Vi{!cz^Cx9XoJMvzY6n%e^jgAt6ur#WQ4{0 zaFtjsSBG*?Yr{q(($%-`#_{x*O5q5RF3-5yC3 zzn`xb6!4w&V&DI*occOTyJt^l`uOCi_TKN!?^~RnNQF9UinE&DJd2bJdUxpOYZRb_vM&N<9AMfb+uc@wElYOnxn$y`}cp{R=?zgSLGW;#Xm8%u0>yG z``()1+q2TRIQpD$rBh<22gBa-^!G(e5}NXKp3aFex*WZ?WS8~cHDRak|Jz!wkl~T? zK1{3nafni?NU{E#yLZ)dI=aQTKZ=X6^XI92cW<|-{=2_NCVV$M-0MG=zwlGOb$xv7 zjpf__|6afI&imKCKC)*d(>v#c%;0LdT3xgTnte)|0M zUoHXh??&0B&KxE0J?CGG=2*Dv^6`ZQNkIX7(luLKCp#RvzgvCs$991qdp;|^o-yfA zrb)Hl1i#5S@$o{%T+7546{Ov;Vq6lkZdJAJIj6W9yEP8${hnW0ET8WA;nCF1E03+M zSSX&f$YEp93DLbXX8-;k+1|3DvwMk?4(~S|1x@9P)w`~@@BFo->1DwNpYgL4VdJd$Cc3a(r?1Y-G#xTP&BdHJ4iZ_?f*t zRZ#x@(4njM?e3LZ(i#h-u8Qj&BFMP@&Bu?R#uyD z6gD@P$o+L}s>0)lr#kn9&&O9zE^*h~y?O23sfI6~h0RF~{c-z#TrAV(!y-oADS3G& zOu^>s7AScx{JrDTU!iagS%$LO=-p4Xe;f6Mo<1+W-eB>az;}}*cBinME&G)7W=i`` z@v!$lkG?C}b$FVpuG!?LXZIEy?cTrllt{gB<}@)wRlS!VC!YA%7IuE~cK>B_C#u|? z{`6tegyir$pW^4oXP!Gc^Gvu>Qq2|>_ItP0zloo}aeqO-bmwEGj~n*X?yA}9X^=i? zqOO={YgxWV+=msyE?zHp?Z`V`dd|{u>%AjaO27NP&Sy}$5V&T_min!^%trG!=`Xvo z^YWb^x(zK3RtF{}F&D*MaO&~ot@;1Zu>N*9tI&(3KjQVX{)IAfDlU7v|NpNIeD{~N zw>a$E@-v)G<;Z@!J^#(zYPI!q|7~UDd>{R+`#le6h!`|3Jj+A@wG4)j7^BD_4~T)< zYG6H>qs(~v$;dtEpU)heI2u>|GJO}kKlXUugw7{_?+RZppFdYsbV75?7fH5223a-Z zuf;o~?aSR)?bv@toT*VVe9jMU9U)=_$LG3*Nn|5;|$gwL7+? zp>xM7yJ_Y640WYCNpswb{C+d+6;c2Gu7z)-Fe8h>sg`p+Dra>%J=Co@Sp*Cna$Mu; z_}J%XFWPy*VPdkvb>}9>lI43YX!Nh=b&2`$WA5%R`R2vSs=f@J-FyM%_MJ~WTi50% zzfoW^y!!XkI}HuLC9W~|*X&ZF}KFtBBT_a?{J%Pi?Z;CGl8g(((p|1kG!un#Yc&?Y*fjKY7KD0!~5ki_EQ; z?wo05dTb~l!IN3D{O7ld6O#)Sgw45l-NjecPpLVUdoitFIgz7KFuBL@+>Hre-zpuu zk{Y_U_}SkjhprWF^oVs=ewQsjtz7@#{x0EpV%@i&GcjhQdX^aK9rK>V*RUd_Ik3WJ z6-UAX&a;VX!p_qiG~9OXul|#8qImJ_gDh;D7t0Cd&GR~DSNCuI^O*a4_r)G}ogV7` zdfoZJ8*i=jf?ip1ZQq-`Yfm*}*Yrbr$8JAoVC-2sp`+jY?OWbRPoo~SyrLXuCxL~Q z$K{M_XK!I}Tb=jBzCU-uM49~DHirADx2#{8F7snt)%9v8m-OmVm9u5pzEjJOZ*mba zkiEOgj-O@0LtVx_dgOJa#v`colA} za4<4#IpD3>@UAfLtJHhLJ+b%KJyt4{T%fgl`Nr+9C6Zq;th)7i`N_vY6Z=Ho%WAnN z+r7!vbnr4fcJ|lQc%91K`+8&BR(-5Hwl(@++1?J#Qir+kWS{GNxf9qWtf?pV`u5>Z zTueG|E-B?*dtG)po#VBIp7)B!K_55%d24m-TxCk?yw_ZXAClu`Vh;3W7N~>&ct07ZE$m(xS=}W{9aQ_p(ye^;1ptvH@an8bzT8%AV zm5%u-ENVaJBqwS4)H%;1^aD0^jXASmsx&nRE<26cc`sJ;qdjF7q|{?|K9L^ z`v0j%l=5!nUOeu1$Mw%Wt{wZomTsEURZ7@fj{q6Cu zJNK=;eAce!eEX*p4FMBMckt`ntiD^O#eY3`l|=K}&;^SO;^JhkU$6ObW$yXU7hcY* zYtvbzr1WzmtK#8}$3BB*1Wq)kfd=&TStsqjD7@!?v&m7{J98R}&- z#iG^V;L86cElJFYW(}SUcylEC>Fd`zi;PYr=e$?g zBz#-ii6b^_p~D%y{zi{UilM<1c`mN8sxh2UGk5c;ci(q&JBB8%+$@oN=S&XcJZ2YH z(?+MdT@`B-lHcrhV3}0vZ&_YmUY?Y+MW=EGNA3Mp-p5~A*laB*QP&3z+#o|YuB1>p!AY)y4sIR78AKQlI4G95_9h~?7y}jY~x01C{g3&gJk42JA z^u-bcv+yU%f996I99w%m)S(aa3%^BM2xLUC^_LlvkGJ}hv4rksNvi<$a zxO2N^_l!v#-}-Z8`N9rQm}ts>_hjqCD=H5bu6}W60_zC|LB;>2Ka<@p=NP}gzsCIa zjtpQUVP>y}d1O`{oJj{`CAbQ=U~54&VEz)M_j9 zM4pAxsQ`}p`m*1P^H2WZ|M&6d))u{eJSV~m|u9GQ;a%I>g+ZNx^Nd9$oI&&lErrUK!|7_fz zKFjRgdGU-&cgfD#9Mk1ASMvybdQ@c9yM}AaY`X~pZP_RM?)XToW9KMi3R3S=?%?{A zckG94E3bsY4*pZMj1z8`%Isp?ka$CT{g%1kzpy$aaQ(cib2L_g$-%eu7YDnRZ^T4J zri+>ik`25oj=fy7l-YMmuNs)T7J=Fx7HSFg&|v z7SG|lO4;>|8-hK~F*iBJB)oa#x8$+GimrogJc72@ZZL#&I5n*KX>rGDMMBTt>5>YE zB{c1{Uaa^xJ5hj9?&^GFmrs6NzZNv@{j7LbA$ix&`^&0MoYg;ED%O*(WAuc(@y@z@ zWu5=&VSLq3T^SfGZhD_%WNLk}-fhW_n=3!a@8{uSEIxE^_OA=ho46({Tr`1GT8T;H z)i-H5=0M+o8x<_6NhfxnOTKmTE@P(sK{F~(1t|AVdb`?Tf+mBuno)1P%)0qL$L5nh z6OifiV0ZXGUZaT{|1W!Ywn`-6Y-QCn6TeMUO5e}9eE4@Sk6_pghk}|X>N(EV{*0WC z6+h>s{879U!#is$)67M;GwwZ)2^Vx^_+?OSr(>TogRAHNj4i7EjE%j?Y?qRX@BCZv zc;)$2VHGeB(WRxmhYrpn`$&#C;M;?E7cD3DR zc&z($xw!b@-E&;`%TExWyoXrz>hzKX+Mv`Z|w>ql{mZKO>`0UF$QE@=Hnk zgcKD2{7sfKN$uh5T#_F1LTIS^8beYT?xF)i?{ zZLVJSG2xY2ep~IIT&xaDUDbX-E2e#BbZ@-sgp0?gUY^pF|9FwHpbu~O^ZX3nNY*Y* zX(rR(TeD_)p8W6C*z)0{n!jd+>{elowDP+1x&JG|U*4;F@m^%fPHpYF1cmeKqz?Tu zyf0Xvv;pg;_I_jn>!4zDl6EYeA?Z(K`Qc>=pMOcGJjs4 z4}Gtr^E4v=^wXl6Z6T{KJ5*K0d&R$q`KrC{Thr4QVe(&$1NRGm-c^3%z@94IijJm~ z(rKG&EM6!mWgZQ>aXZE6-)!lHU+;-m{cq*Ey~g~tZ%_9OE3xAHf1jOPE3)q0)laT( z!?)k-p1yCxh6WppT*awN-*a+|P9uT=B#xCp6bg!nEsqONcu+0lB?b~umeAn;1-=$X`75)6? z-5?UC-OBnVGNQ`(bx@3rjK>76srS}LM93_SuiP(QYvJ^U%5wtc_L~&rBEyzfpG^6E zbx-`lDTgktj|kH&J(<+g{WbYj>gu%C)}z0fs%%62{Kdqi+qYPjUY!`Vu+C2Alh=Nw z$c(-I*X+wvzkaLSxc6al_}yQJ_C?h99onY3A^DY1@O^QyA7aO*1eRmY33Rtxzn2#| zc4_m58PV^Bw^_5Szqk3o+1#+$JdIk#Q=c~2amLkM>n;yl`#)~;nnK~f|2<6Kuf6bg z%b{ztzpCkp87_5MK7HQNvIL*=o2s;1wa~CjmQmmL9s=Tk)2gn}4Fsl=vevJYM%6UF)~OVk4iYj?N61P1Z*? zh**Wy&fj%0?$3{VYks!gzIr}r?e{~>(VJEqtdCoJ=8(l!1C#d~nffQbk&b*H?DgBc zXHS@d;*#vu$M$_mEkCx^KKoO!f#3QoYk%GFoVL8D>ej6H*B`yNeS6CzR<%0)re4>6 zFTL;XA9u;_`1hmn@5^{m4~}qq)z490{?EhNg`CdU%_-QM>u`=)=+Ia9%^?x*(qlkM zzSOne^(HvPTrHbsBQP}<sCx>u8SZuUv3+O>Q4?%j{GcJBHfn?1{8 zNzML^Z?4{bd3pZkBD3`5Tm8q(SBCK|?(hG%?)UvN|AQjOU-~>qXMWkH<<7-6M|0hN zCV>Ng4G2vLl#~~#eXqXdT|O&jj!yM){yV>~zPmr=_cyf$okQaha?l*YfS2 zU|fV(`KJCktSkv1z3!j4mv!>UduPkPxNH0Q_q9*=e$R`0X~)^(x9jrV(<}nZ#igp( z2Rj5!+WVYs$Je8ga(t!}!nl44{Qb91xIFBAtVNRb zA_;Ht>$9gbFnU;U&uK+W2s~Y?zht-d+W-V*2&2 z*m*_Cw7Tc%8d*Q}PQ$n9i#d%Dr%lGpl_kDI=)cH&r49OxCZ zX1@f7LzN~=#4eG?d6kVK@$1hwi50(3?G0HU z_hiM--RqKd=k56YckTAS%C2FjlKD9wK7XY>Y4!b_OKmwxK67W@E}C~jn9JLl>BU~_ z>gmd?!X?R?&!0@1dGKLLx!0>*B9E&!8>jGezPam_nm@;DNl((d*1fxbx9}Ezd=z$v z`}Ffp#q)Qow?8_%cfQ0YyR;o2SAJIX`{k~yg5bt+#jjx-;@lCbif zMr(~t|Ayae;meC(UF_eiQt|QB&5*}odoFMr1}=!ue9{$n=Ir0!Yn+{K9B~a&oW@oy zHet%d7q)j_AC9RFI#^;6u`FC=vjaosqO|ua#^q)$&Ps|8DBbEln@^bhwwdt(8YN3?R8je~wF=YoJ8H&%a@YH0C| zQ88rqv}N{K?l~v!&g$@aUyohhYvFC>)oL0jSD<~G>E*5~OLyFOAHJT+BO+hSlVf?a zKjTF{r}cT~lx(i6O^EZ>yqmab$Kp>1cI3H59g%o^(crsPL(7Iv&qb4;vCn<7pr+j~ zqV~4qJmYL7?j1VpKTq<_ov3j4chH1KRo|C9U(LL!Z|;TZ=jP7l?rV%$%`rFSW#q>* znL0ZQejUtteL&Lldr$yqY<|67{58k8wi}(ZrF+b3AA3zGTvH_WzVrF|J)XN3Pq~|z zabD8X+}y(Z;F|s)R~a~8yBe9BOEs>P4iA{P?S7CwgE`_|T`r^N5kPxU-k z-4V|}VMFIeZ?_9M>gSL7RnDkR{5miGjo)(XoN@=N61QniQ8pXfKXo;<^~fhRl7WGN!PC{xWt~$(697y)>VW_N literal 0 HcmV?d00001 diff --git a/media/extra_grf/rivers/tropic_forest.png b/media/extra_grf/rivers/tropic_forest.png new file mode 100644 index 0000000000000000000000000000000000000000..1aa21e479e6df047790bab0baab3dae7f3e6ff1f GIT binary patch literal 15157 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 literal 0 HcmV?d00001 diff --git a/media/extra_grf/roadstops.nfo b/media/extra_grf/roadstops.nfo new file mode 100644 index 0000000000..dbb70211da --- /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 0000000000000000000000000000000000000000..598792417be2b5c748ac3c99a254de6010e8dbc6 GIT binary patch literal 2621 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYU@+idW?*2rH{o3j0|NtNage(c!@6@aFBuq^ z83KGlTp1Yt3kV1(C@2^h7&tgM1Ox=6q@cI-HD;>3*`H(tDW z@#oJU6B`c~pO}b*f}E0;mYx}N7OdH@kDV>^bn~0>hsdHh=y!_-HUB*l?6Y$aIug%;^Z&Fem58mJSyQh6Ej!1{aPw2?9GR zB(BU+c(Fs^&lQG0KN|l0IiSG8;2^>gA|sHaBhz4^F~!4TMU2mmoQNY0Iaj7MaF{R% zI4~##uoxt;I27=Nw1{L(k!e_=BV!_=Jof8TY3>GpB9vUnWCOjDq5;Y+@Jvj~w8X|l&1QJXnN?bHL zLM)afIP540IMa}DWlF(=6%B9pObL)-Nzo9gu+Zr7aafR&u%n|xMZ?9wB*eiXB_N*J$sZGw zKPeG^Ce-}dvEa{*6Mw$E@enD9(dj90S<#bnWJSk=6B~Y9*zy0xg+De73^5E04Gatm z7#NN)Fg##j_`|^PCxGEk4#S@ghCfRf{v2TVbBE#2ABHm>98V^&{F%e>XM@3?BPoAw z%;1oS;8DpCF{zPp>CuQ;Vo|ZjW5$h?H4kFunB;75s5#*?;X%xUFMm$F`LX5Bo0dH{ zB4(`l!tmuQ!`E*N-@Y?^|H1I%C&SNQ48MLe{Qkr6=P$$Ge+>WrGyM0F;KGcXt!FgQ3c1Ozbr|IeV{QlR2d zqTy4a6HsFi(%_LYA*E%-jW2%^8kV>u^!)$-|8%(bLIwu5*PbqpAr-gY&N*K++e6^k zao+_uuDoo{2&rahs>8@YbpWyzSYdE3_b1%DIck|o!~{@zRt zJ+k89)c41)^Qyd2?{s-3l3m&Tb-iVD-R*CTUvKV+&wTUge)Rm3^o9-3X8F|}cK z*Zo~}Z`^N$?pC;~uTWc;ust{3KHqnNv~c2@`{_xARmw|~dKzk53}IAVSF z?>X@zrelsc42!x~$xb}jkP$0dC8JQ#@zn3+1RqmVhl-H5wtU?Y60<}! zyA|Y;G}e@FlHF>?+( zf3#ExdY#tAa`C!;?6Pp{4cQZCiexT3$KbHV=;cI4#jAdm*XsWYxt#qHAkCCAsiEcP zoN~(?M$Vw4XO=YZ3(RW}eM+b-uS1-TEt%Vxa2D#aiLRHs5|5 zvBaJB*&82l?_(6KUiFUArP$$#it7^&hny;p*>aNNtK=tG**5g@s-AFJpOpLXj{MUO z4{L=N`T7c_RSa@XtV%mrSe&1TUS@veeCE@uBOf$tJU=9I^@{EJ#yDvS+e9nZEmDjg ztKPgxyu@r{&oIHnSLk|-qQdO_lvOJkg_3U{{%r0uaoSt{Yr5QR=km>`c=robFYoAN zFXZI-q^e-+b4z6T^qoPuOh>dfCwGWXIHH&oO-2LsA%RFvORp>d$ZLyzOK-g$uVQI}og&*n69BYh^J~DP#uyfK3MX8Sg zGhZ>Q94)R|byy&XWxYviG6SPiOqIlCeop}lgX=N5XS8Q#Wi@nY@Sm+Y5Gl>@nOR{j zr;zM!gC7^?I2r^RG%Pr|Y3ZX+HjWE+7HLj;n7Nl*ljloj#_94lFz`D|o+um7Q}hcLw`;o}?2UIxOAX4n9pgJdc%SyB6D77WWU>%h>Gf? zZ*E6pDFB5;9WE6Vr`})E?tuG8pyBIXnD@)lpu4S{UP8SRrf|MP52nd$<&arzvVFd4coWX5f{}s zn3D8Amc4H-Io_a?^Evrh^Hb5?D;Oio?p#WH^C9NyB58q=q%xUHjGEO~cl<3Zf56G$ z*{13d%OSgdV|VjI=0ESMYwGu=z0-KGq2$>tZBXX1NOm{yj$!4nlYhkiMByPb%kA2i z^Xyrc9JuyTXz$&^w&@o#<}xJd-Yu(XcjDmKQe;shBNvd#n)3J0r%!wA8hSYw{Slb- zPJV(!dT0A9^V-{tk)jDp%pt>;o!QI{ah1-|4O=Xe<^zsIsXyQp&J)3<$mRF z6_}uKb=7k9>YAA3z0;q|AO3$;>17||%ID0+-hbrVZ>&o=$67V}_jP3jckk^?G2&M9 z|L$g-X=}Squ|JK4gRv-S$I_Xqb^;0yGQX6WFidD(8qK(po0l!cwz?^5vniufgAA{_ zT}0CZPx-xf**V-Dvb@W;Ml2IxblSxzke1fze?95pR5g2r#mQ2W0=9%b@6B zcSx};Bci+2Dr(o(f1ce(*>~K%^7~>dJEK!WjevuUO3sO2w=T{7y79tES#NuVfcL*Y z{9oSf(on;+V9nB(`g2Sw9XwQ+T0nIG7D`Y-MTpT!36-i9`pdquw{UjIv9)^`7#J8l MUHx3vIVCg!0IboD4*&oF literal 0 HcmV?d00001 diff --git a/media/extra_grf/shore.nfo b/media/extra_grf/shore.nfo new file mode 100644 index 0000000000..7b7c12ad3b --- /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 * 52 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 0000000000000000000000000000000000000000..f98333ebcf0ccbbedbf54a8e49218458ab4b837e GIT binary patch literal 21568 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

    aH?LT0Qy z8hFY1V-ANP#4mm zAyl$JNOaBBNk8VTW1o4tdCkcs&rfDA)ppt>F1n7<<599B1h`Wh;NcHeoq)-yxI2 zjZ@eo!@H;I`_JsJv+?Ddw(4!x{Ed_Uaa$^gr?34uUts;J$W3CRX(y~L|NcBPSxxxB zP5%aFX+a$?`^U8p3WN?n^1t-WU!6_CUcq5Um{;iH(=z<6%*le&%MJNAt(#RocTd

    c^za-*g#MQX9Q%(%T8vbN3 z1X^|-E(`i}J?v@SD!U`vJLOW=?#Xys^ySdg&zEnld3;g%_=c8Cq7%($+VrVS{+MC( z>wJolq^(V#`r?y^JHGX)J=UMB&p-L%i<-PID9*d#bKU9H zOXjRf`Bm}e?DaU&Ddls*W_^78@M7ly$JiGumU_*+s*pBG+by%sr(ubBn1zMcrz&^$ zduOU9_^!*Eq}l&)qR<4Pd zy7HMRLuA-1=6wp%=g(Vy(Ac3?>vk_m^MsgqmG$A&`eSe3GOAa2SWYWg$5SBDAklCp zZktu=%P0}6iOWAex_Tn8$Hupz+J0@gX0c}Q<+_lDB`UFxuU@_$cYE)bqpRJ8=Z1IJ z@9$%fYWP#YQ28k~rucWW{n@u%KEEe2;@c. +// + -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 0000000000000000000000000000000000000000..6e0562a392ee5f5f773ecba3b4bc0776afbc1db9 GIT binary patch literal 23747 zcmeAS@N?(olHy`uVBq!ia0y~yU{+vYVEn+r%)r2q$^Scsfq{XsILO_JVcj{ImkbQd z3;{kNt_%$S1q1{X6ch{$3>+LB0s;b3Qc_AvN?KZ4rc9Z#V#SIbJ9eBnapJ~}8!ukG z`19wFiH(PgPfSEYK~70aOV5ls3)XDdapcT}I|e!|4mLaiJ|YP*G8GjLQ>LVB*wAw3 z%nA=3mIxb>i~yaQ438NtF*_DiT-h__%bg7l3@i~W0tEsJ9SSB3EPVEa z92gV=SPT+a913_sT0}CY$TY0bkuj0baZ#{|FbK%7$*A#Zm=ZH%L(Y~nH3B9Q3LZKZ z2_8Nr5eXeR6-zp199XgA&Ittx1`8Pm4-J+G6P^qQiJB0do*ah-4G}&X0tqG(B`z8r zAr?y#9Cj20oM}k7GNs_biiS6PrUb~aq-cm#SZMV4I4np>*wN9UqTym-65`;H5)e?5 zlG4%AvSiJg16Qs*&=4tb(3ue7uqMOjNJYeho{T>WI{xfg@rOYohe4%)+cv%%ock(56- zW^hPE@Tg>nnAFI)^k~E^v8dSNG2=$cng=m+Oma3j)SU2{@F3>Fmp>=o{Md5mP0OAe z5i{0&VfgZu;p;bsZ{Hcd|6us>li}wthF`xKe*aU)G+*+!tiGe!=EDz4h#(c85j%<7#tiJ0s&WIAp=8Xp{I*uNX4zUv9V>ht=6;7 zb)FcMQo6?;EwoXSY0}d_TaQGpPJbJ~|_KwEsfgyQoa{xBqtd{uh_KuU@^+ z7CK>_7joyZ$-W zVZsWRFFgWT$0AqHf9B>fTWP|tKQFWXcFS$3+J8x}?T5atUC=!Jqpshz-#-0#@fD9y zW-MDkmR^v^q**0m0xeTE1t}k3`n#kher+t@{Y%U}vwy|UN_@hz;EILxFZD&PZv%70 z-)s-C*Ntm-h@bK}G<(_#6@gOTBF#yv+?s+tF5n; z@x|h63Zbh)CUPy)3SD()fXh`~4u7i%J=D|Hs?>j}}n*(=sJ% zlZdnmGwWH0XXz7y^cw3-0xs};G49}7*qV*4O5|<|n*2@BXUiH~0U2tN+q(lOk^%O{iekES>&7 z=}p4)#zb!64fFHGm!JEeKlgvM0L#X$f10I_9E;RW^v+ON;piy;^q1$MSL~_fZbwT0 z)qnhx?t18C?`s7&zTfunTilT+)|aOhX8))V zoV=6$Z^zb;bE72l=l%CQ^2EAW>#^{e?^DkHXZaOe!`(DzPBM$bozpW;?7Vm4hsvX6 z#!P0*UMe&(n6<_C--zOzY}w$48s{Y@$0!Am%>Ahf zRh&;|#T{6dzkntC$)vX}s68NbxFk*03(thSH6Pkl zce-9F5x5wh_;^>F{-f)Oif_gItLaBHmk!?oX6-)_0zZPUFjd+*Q$HI{0G!!{WckK3kaxpZK=i^t1X> z`=Do=pM2=jecbx-VujqH+567^W>Xj2`||dM%w)D$VMp`%`9-~_bL=O+e8rr#zEs`Z3K_$8=Gw>_)F^OS0F-eu&p?y|iq3`D30% zX$&80rmU6BJ^NFm`nmPPxafTMxNSpKaw#c-d*U zJ+AqJdVF(6;Zm=uT2mE5SG|x{IQ5fXeB*R^&Q=E2-Hb!fEe}VTqO!X?h7#vY;YWOF} z|6l%zAm^tQ2`>~{j=NM_)y?{FZ)eRvZ_XyMgC7gJpH$3Ki2A>@?9cCHzX|TF-LgF2 z=E#WXT3P?Uc)9Q#L_fE1L{Abi;(KA7t(@BwKrozjD$seb12t|~{ zx=c8tWcf_&633!m{bGi8mWN_7z7x7_!v$3~78uo~`FAR;bWW9!;o)rhd-7Z41jmjJ zrwwIA3D4p;W`D2to3OXIv+!BLzGEBtC)eGZU(3)`QNl1&LD8mdf`-Z>m*16t#1kK% zeI8#F@JxOphwdb6kF1H6K2vTl-@`WXSi1ZHMjN4)XaUYiH`YJ+a760-XMf$OS@mXh zY3ExM&df92F7NWr6cEV4YV|zlsl^ zvjtQ2 z%j_6u+_XgOrkg4+x;cJqqj! zClXaUET=GY=~~QxsI+gcy2oovM>m=0g`EmM^-ZPT}=zJ*3cj{7i;oA4A zO+IhM4{ee2UUP4a(uy1JqGu``yE98+?Q~9~E!-@Umq1oj`ArZ!9$9lzqnq>5?H+}< zp{m#R`wG~6Z4p-a>ZdeQ!SlC=Kv?qb$fgsj^DexL*4b$BZg%wah_%zb*DTx{!_<3E zI(bjNt^P(gne>mUi=VJGnx1H=?N$}D&P_e|lc$((PQ}}(ra2$qaxB_e(yflBVAJ_&%cOEARG%!ijM&7^FKdEc*H9x!B8>N>-{J znYQsu`Yp~q@^(9UU19Caqx+7!?y`*8diHlD$D)VZl{+3R@T~HbRq5h$+FWr$WA!g_ zuwjyib!SYEdG92!jn{hFWC`V2!e^#F^mdEfbGBP@+Vq&I3fmPuCdHWvAK7c_xWjov zyJd9IUVg`#*#b-U?w_SFy~ikhex!}C!vuv}Ke^(&6*}&BDx73*z0G0tV7oHMyCg-& z4Nt1-o0i<(lg-KWY)0&-fl! z{NL^KN1kZTAWo+lhW|>N4zRbz`))b@ePjQ3?Hm5z=Jl(cc)p4MZ?Etgl^bFQSF>t6 zt_o@Tvl>=Kdri;^)pA6tv*7|koIy*yR6QWISV&XIN)&-VqAZGCfxkK*EuFjM+m1)- zeXqVQiE#;(`%r z9`VRs<=G$j|9DS+s8#>zTbk>%KKsEOYUje ze$W4jOO8zab)%$Te`i0Iw_otzTCo1bpYtr0E$sg+UNf8%mw7PJbW-^y<_dS0>gO|< zeWi?=e11vD*=QVQZCdb;(fa)HpEHD?IKOq~f2eoWXT83R^kaF3{Y!ovEM~7@eDnSg z^Kt$4cM^Bho%$;LBK^mA=O1$)$*FIrE z&#@mkugO<;T;`GF26KDnV9{{_C$9+y7JZa){MOmTQ>`w<^7}N$qX`P~Ir6{fdvk4XYI(|4m_uuTE$EqRd#BuP}B4&Z?CF}0;2Ng8z z^*$A%v?#<@@bmJ`c778+{}nlHVJ&~i&gWNU{WnIAM_Ypv?%%YtKCG;kwE43&=X-@D zrEleKN49)cGMiv%v_{}bg+Vzec+Ly8Oc!ZpwwWT^@J73s!QA5@V^ICP!UsJH=jLh} zC0U3|7rF`fIoKt2OS;&q{ha%D@wErmD-M=NG{0ZKc7JVjb3@&!uZN{lwrBAc8I-#n zlDGOF*_5K%8szlhn5$`-+k`DFN@Be$vpdg;F#g@xB5R+>;bjpsnL%-l*M#zI{y$E7 zcTG?4E4LPB_$+njZG=lL+nWV!qf12x_(%Ijg zpZ~YybebaE@*-%Wjsizv)0r3kAClXTtJE7c1w8(#B)K8i#WNC% z<@&EbGG$4eop{5}G|pR~?80wpfh8pqYHoilKD=J-#O#~w@;{azUfX2;^8Z)&!^ao5 zboL#$->>p!w^5vAZuZJI)--2q5lJbC8P+;qR~3LTbn zS$_NUzJB}pCFiGQKf*u6N>|E^tVn^Y^+QO}At*s{;=eEDl_$xWDx~$gBqk zYF{1jG_fmvs~Kwk(4yO$#qw*K*!I}V-Yk(h^Y@9rF*a5EJag;$8*!YQ4m6fBWw1=* z^f26Ju6AN!Hb2M!j|oQ_kCzA~zuCRb|Ee#j#$h?faf#XS*F*(2jziw-F86XyI+K3Q zF8OzeaI){;^AG?3o%G?O#>4pk%|bed_t^Jo9&;{EZrT#3cH)Ab;F9^LrtbSXM?tx7 z^ADj$ap5D|B^@J9UNtvYJ7F@vvWe&I<#k*ZXVMSPYR-S(ufOQ}!^ayNd$zCz_pop=}6Yzm?Yk}PMlM$Zm;~h=ZI9{oTJk@<_NP~Q(*q4J1s)yyZ778TaL_nW*ncy z`}Xmoy^p)&j$A353o3?uwIA`7EffeY*H2Ep{nh!ozo8tDz4&fZY4Mk9r;9Ii-o2s2 zZ?5h|c8DM0wJKv%!S6X|j=BDd`dx8D)X8VXJ8uVJ;9OLTRmLhiBRL_kIR1rpOFub zE1G-2?yvRj<)_@aj%FA&75ouo@m%~dsww6JThoV0r&Cxe<9~^%B$H@|1W zHrMaWj@P)R#bnI?*Zem4X)|Y&>h=BZ0)JFw#a~WU_%GtPDRxTz9mWX?SM8=M1a{2` zT~({)xQaQXDJ0Tuf>!7%jM@{o0JzpbsgTb*O!yr6((u?J{g)m8gLBk_ZfAP$HrRK1 zZISiFTYk~ERDVxQvJZOW-c>toOZe~D#Qm8OBAIn8OC&6Eh2HC@tTz2V{Z{6#pp5W$ z;>Wgs`M2K6?iuINvZr+~f9matm$29Trkwh3$&K{|_8&QdQ+7;p^yvQJ)fTxbzQZA~ zvmuJ5*Q+IF$^30DFFbB5{b2gLWvNrgmbFb03+8W2nc#8T=**w@*~jgtyKnfxxZ=C^ zTaoow&!+|DU4IvTOEYfu{3#zVZu&j7>|oukKN?zm8ak2U+k^Ln{Xc&5y_1fRw}z0U z-L}a^_A7razE;07w(CK%wdVK9tL(G>iXUI!qp$T>KWqA%<$d~EkGsA8bKg4p@u+{+ z{$1UnOS?98hc5M+s&V!Ep9iH!j%|E0<>6ZPqteMPJ{24G8m2w{>vkmidH>(Lb^o5_ z&-?GX#`^K;o!^poZ~o(ZOu6s#jE;==r+x`WAJ-JrQ11B1U&HiI^(g;5=?API-nW0S zK58EqUw44n`qYoUx#vIpI<(QSj(tXN{_~&A^^noWLp8l7^^4EkZ#aDR%>5HT=Fj`z zD)8iwjpLrjEIS|kwLAA%$kE|{NBe*NPcwv5o--R?IA_1y;)ks93F8O%AF8XLIBhKP zqGH0vM81!o&TPEd*nHqeSzUTU%^k%DjFq4NFnu!cZ1YyEIo#FQ$6l=du)RU`sI1!scFje04o8l3yn27AIiyJ7#qpo^8lR5~8Eb1! zVfeWI{Cse~`GLTt;-KAS`=7Jiw4N@KSZophcnP#NP3LH0tD4C3Wsw9&_J!u1#zK7d z3zrx~b_%MnbIxj>G2c+1e{+C8waKD<*@+HaLnnoEoI*~k z=69Uf*T-^@=hE3J5eW*%uPaOlnt%6{=?PhLjz|0V9=QPW+kcxw{tCx#Y%Qx_cA~{n zQDC=is;bO+g-r2>*6JN|6+I41^4>73iRSxwE%)BP-?7Sxo3rOy9wC*_`A1|S#r%mo@bti=0Eti_Q(Bs^?m}oI~B_Iw<)Zh=Gb?9nYXBt zTGp<|8+-cQ*FSh1c&L)aX^)|^?uGgDvb%3ctmFUq?c@K~pXV1o@MTflrRn(3#CNim zi_aC4v-6GqeLY@YU&m?DBEaJFY~NE&S(E`_8*Yh?lXsfyj@E?C}L=5s>y%*S1jk?BP$~Ka#??Kz@VOJ~PGZ5)t8K$*Qe7?O8(mG5Kxa zVO*J0KN2d=_EdcSVaonm`hGrm$oJ*x9qm8A-TY(T_kXi+i$;9$fkjaV&zh~Vj;OxT zRNAz~VS*UPB__vPv-{%9H*C9)Bowvl=?{IQIkG)0nYQXDIv(5T3AViSH<%Y`v-|Ar z#)A^?60UO^mVP(7wykn1mf>B`&aW#uA02Fz{N})MWHJ$h*|Byhl)X+C6sDU-(8@~ z@X``!rzxZCCyeQw%IyW=k_}+>$_F9j7k3QcSv;TtM zmIZUCou97qfA_ZkuHTlO-rPO$-2XF~d$x#+_`N;#H)PhtJ9@G4NlWg;?Xc7Owdh{_ zor?dDI3`N%y&|{u+oWcnU+dq+SK0+`aew)1>3);>zxu;_{ZA-3wWzB$Pngu`ane9! z`oC*&Fa6aoY-MzK?a!+a{&N2Ax;@TW;>WaGmzXfeuAM*Sxspx^OUagNH_)8Eh6|9S0&x~gr)TkT8k zF%k~pU-xS?`yAXMBIt3(09+}qtB-6^Nac0X&aMi&#<66Lqu93TOy5c$tET>2a;E)M z_Jr17tz}V{_FZ^5*<1W}`#SmfyGK_ArQX#Go2nJsBBXs_zSF$P=iI&L^RL=B$NFts zS$gMQo3B0X$@iE4UOU@AGrcx=m+CB&bI&hq+}qIE@hva&f7Nf3>&ARX-ntrvSxLOH zG+FjpJ@H?2tMJz|^B#Xq@G}VS+xgSzZ%1KN{UV|C5JK{+MZd{Pn>(3F~BvKQH|@ z`z`}JM%$)<#prali6l{ju*pQ4aAK~OlA@7IPlg>!R{$0(gh zl?^@OG2!!vrLMbbMLC)zmrUlEq#LFFTh#p7<$It}Z7bt?_U>1kYrXjnoZ);n>#(Gw z-eLFZxzD>Lmt5vJgksswQ+7EM`&dqTtm8qbbN|Sw zuX>_AZNiZ`+(sT*`>xb&{%gDHbG+LG{<8|Mzjf3-HgzBMubO}R*;!7dw?ZFZ>?(lN z+v{G%XCCLdRJXrL;gFtKe$2MB-7KEvGb>Ey-9MJn;xK1czMuX5Z%2RD@9%;r*m8EZ z;FGA|H9}1{q=i*@8*g)7x~J5*PGA362lf)Gj-g%~>?J_Fk{T@y9_;GW|x5lfGR{>^rW?Vkwu} zH09QQ7RNKS*=e!|O4fRA1$AYa9DSCdm?!tYItlfIq)d;IbIcyEqR&!_uL`1$SeM>Q5pIc}aK#~y#Icw&6y zBhTAAjC?DZ)i3_om;F9CSGaHU4wnhPn`a))y)Lulr}X9t3hm7f6IL3|Jin&C=dHoN zenw+Wh5{c8h_<2_45}-?|UC2-H25R6U>IsNk{luYa*{)1P0# z2?}QaxE|M}@fu(m6L+})8xv=2ayVI<+@$h(=GXp>vYeOHzghZzdkOBrSLizGv3m&5 z`BG=MqxMz8ffo(?bgeYJ^*axXd+GRbsGOM)IAOuQsa|V}e$Qv~J9m!b(0gs6BiorA zmmQle@Wf!McKfyBrXFw~InGDmei}>SH!Bl!SodAXu?;j<5PhE0=ux>U$He^q;VK@p z;yU_{|NlEl>}B%rn~DF9b5Ck?aA^4dGc0P!^xOUJegZl>Z>{^edBqVe0|Dvvx*Oj~ zI;y4b&bNgQp));)51}7tKcP^0a_c5o2Y&}!BFoF;`~22ESH0Gu&+@SUzb>cJlnBo% z#jL#{Nvdy~5C7WoUvcphNgt(-E9Z1uRHx^Q3%0Ddz-T74(Dn1r^SYNVyOzAlS@yL? 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%0DdvURT$?_T*jk=a($ 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 literal 0 HcmV?d00001 diff --git a/media/openttd.16.png b/media/openttd.16.png new file mode 100644 index 0000000000000000000000000000000000000000..4991aeba441a71304a2ffc32d783a96eaa2f3353 GIT binary patch literal 894 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7Sc;uILpV4%IBGajIv5xj zI14-?iy0WWg+Q3`(%rg03=9maC9V-A!TD(=<%vb948DoUMftg@DVd21Zka`?<@rU~ z#R|R=3PuJ7ChcWw&NDDDh=DXX7o{eaWaj57gkf~CTD}^%0_itJgdihw!nhTaz=|^mToOD)sw`glv}j7Oj)A#+B0h1 zG{sr7md8e%zGhk#wRWM}rZd5Ehn@yJ3-I}J?oayRFUQk==e++OSHH*pJwKyEm^8ci z{ODiHdRA<;S5ssYF~dko-lh| z%Gi@rnb*2C%q0wl3ztiE|sCP4j<| zSJk-OvQVO4$GK?5a|J~<>oAs_L=KtaNv)SRhq^C3v$y5mzq%6B{Ra{jxUGdHuL_k3$u>p?_k;~QWv+e*(kWHKU3sZD653* z<%BH3D{=GsT2*8pH1Sm}GH*P;WV)cz71h8!6~b}T+;@K2!CW`@cIV3!+nS2iO}pYc zpL1EpJ$G6B^sX_F*>$E)7UoU8AEw@Zm>{?O=&W-h0_IuuK@n4hRo;p$axP2ua|?){ z(D80zVvYR81-qAXua%X(aIdi4Z58)^j_4D=G+0D8Z8e!y`Xs0$=ew<=pq8G~{x_~p z2E2#Wdktpo5bd4H^~LN;!lylg$Cj`hDo|6Z(qIwanBMbMXUFMtC(6n@CS5I5{P(75 z$$?l08%OVD(rzO2F1QJ@c;pD&^L6|)!8m=D|L2&E9)9=wKAi~n6WG4%!ITQakC#~{ zcPmV^XFk4bj$qKKndZjZo~(^b4X;1WQfQcd=)~-~MHBPyNo_vACy%-N==a@cvKB{Q xW_?|y=Iq2BD`Z~1fpg<>{kJaHD^%axhj)~@OyG85VPIfj@O1TaS?83{1ON!QhzS4y literal 0 HcmV?d00001 diff --git a/media/openttd.256.png b/media/openttd.256.png new file mode 100644 index 0000000000000000000000000000000000000000..596ad19cc7876b447e4ba51f46cae5fdedbab41b GIT binary patch literal 16161 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 Kf=igizyJUgCQ;G= literal 0 HcmV?d00001 diff --git a/media/openttd.32.png b/media/openttd.32.png new file mode 100644 index 0000000000000000000000000000000000000000..469f16d885c87530503dc226f52d955a24d31410 GIT binary patch literal 2475 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 literal 0 HcmV?d00001 diff --git a/media/openttd.32.xpm b/media/openttd.32.xpm new file mode 100644 index 0000000000..9cebcf89ec --- /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 0000000000000000000000000000000000000000..fa0d989baed1ccf119f3c13b5e87c0453f3e3dce GIT binary patch literal 4551 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 Y{nVLnxnF%P0|Nttr>mdKI;Vst07J#LXaE2J literal 0 HcmV?d00001 diff --git a/media/openttd.64.xpm b/media/openttd.64.xpm new file mode 100644 index 0000000000..879bfe6f68 --- /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.filter.awk b/media/openttd.desktop.filter.awk new file mode 100644 index 0000000000..06cf1106da --- /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 0000000000..513ff712df --- /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.translation.awk b/media/openttd.desktop.translation.awk new file mode 100644 index 0000000000..ee8fdd9700 --- /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 0000000000000000000000000000000000000000..b2b12cab6fe29b753e6fef3ef136e2c4cfd4b803 GIT binary patch literal 39814 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

    %ZB9y#J<2F8@`8 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 literal 0 HcmV?d00001 diff --git a/media/openttd.svg b/media/openttd.svg new file mode 100644 index 0000000000..30aba231f1 --- /dev/null +++ b/media/openttd.svg @@ -0,0 +1,265 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/os/debian/NEWS b/os/debian/NEWS new file mode 100644 index 0000000000..2a5c811019 --- /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 0000000000..e7b4bdb135 --- /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 0000000000..67b0e802c1 --- /dev/null +++ b/os/debian/changelog @@ -0,0 +1,1076 @@ +openttd (1.9.3-0) unstable; urgency=low + + * New upstream release 1.9.3 + + -- OpenTTD Mon, 16 Sep 2019 21:00:00 +0200 + +openttd (1.9.3~RC1-0) unstable; urgency=low + + * New upstream release 1.9.3-RC1 + + -- OpenTTD Sat, 07 Sep 2019 23:30:00 +0200 + +openttd (1.9.2-0) unstable; urgency=low + + * New upstream release 1.9.2 + + -- OpenTTD Sun, 07 Jul 2019 23:00:00 +0200 + +openttd (1.9.1-0) unstable; urgency=low + + * New upstream release 1.9.1 + + -- OpenTTD Mon, 08 Apr 2019 20:00:00 +0100 + +openttd (1.9.0-0) unstable; urgency=low + + * New upstream release 1.9.0 + + -- OpenTTD Mon, 01 Apr 2019 00:00:00 +0200 + +openttd (1.9.0~RC2-0) unstable; urgency=low + + * New upstream release 1.9.0-RC2 + + -- OpenTTD Sun, 24 Mar 2019 23:00:00 +0000 + +openttd (1.9.0~RC1-0) unstable; urgency=low + + * New upstream release 1.9.0-RC1 + + -- OpenTTD Sun, 3 Mar 2019 23:00:00 +0000 + +openttd (1.9.0~beta3-0) unstable; urgency=low + + * New upstream release 1.9.0-beta3 + + -- OpenTTD Sun, 24 Feb 2019 23:00:00 +0000 + +openttd (1.9.0~beta2-0) unstable; urgency=low + + * New upstream release 1.9.0-beta2 + + -- OpenTTD Sat, 09 Feb 2019 23:00:00 +0000 + +openttd (1.9.0~beta1-0) unstable; urgency=low + + * New upstream release 1.9.0-beta1 + + -- OpenTTD Sat, 09 Feb 2019 16:00:00 +0000 + +openttd (1.8.0-0) unstable; urgency=low + + * New upstream release 1.8.0 + + -- OpenTTD Sun, 01 Apr 2018 14:00:00 +0200 + +openttd (1.8.0~RC1-0) unstable; urgency=low + + * New upstream release 1.8.0-RC1 + + -- OpenTTD Wed, 21 Mar 2018 21:00:00 +0100 + +openttd (1.7.2-0) unstable; urgency=low + + * New upstream release 1.7.2 + + -- OpenTTD Sun, 24 Dec 2017 14:00:00 +0100 + +openttd (1.7.2~RC1-0) unstable; urgency=low + + * New upstream release 1.7.2-RC1 + + -- OpenTTD Mon, 11 Dec 2017 21:30:00 +0100 + +openttd (1.7.1-0) unstable; urgency=low + + * New upstream release 1.7.1 + + -- OpenTTD Tue, 13 Jun 2017 21:00:00 +0200 + +openttd (1.7.1~RC1-0) unstable; urgency=low + + * New upstream release 1.7.1-RC1 + + -- OpenTTD Thu, 04 Mai 2017 21:00:00 +0200 + +openttd (1.7.0-0) unstable; urgency=low + + * New upstream release 1.7.0 + + -- OpenTTD Sat, 01 Apr 2017 19:00:00 +0200 + +openttd (1.7.0~RC1-0) unstable; urgency=low + + * New upstream release 1.7.0-RC1 + + -- OpenTTD Sat, 11 Mar 2017 22:30:00 +0100 + +openttd (1.6.1-0) unstable; urgency=low + + * New upstream release 1.6.1 + + -- OpenTTD Fri, 01 Jul 2016 00:00:00 +0200 + +openttd (1.6.1~RC1-0) unstable; urgency=low + + * New upstream release 1.6.1-RC1 + + -- OpenTTD Wed, 01 Jun 2016 21:00:00 +0200 + +openttd (1.6.0-0) unstable; urgency=low + + * New upstream release 1.6.0 + + -- OpenTTD Fri, 01 Apr 2016 21:00:00 +0200 + +openttd (1.6.0~RC1-0) unstable; urgency=low + + * New upstream release 1.6.0-RC1 + + -- OpenTTD Tue, 01 Mar 2016 21:00:00 +0100 + +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 0000000000..7f8f011eb7 --- /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 0000000000..54e14ce5d4 --- /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 0000000000..24d6d7052f --- /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-2019 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 0000000000..58b68d336b --- /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 0000000000..3afa6e08e8 --- /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 0000000000..6f85f00b06 --- /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 0000000000..ff8fc15aef --- /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 0000000000..f7cf2d9d58 --- /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 0000000000..dfd39253ef --- /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 0000000000..163aaf8d82 --- /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 0000000000..776381b9c2 --- /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 0000000000..112b02a087 --- /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 0000000000000000000000000000000000000000..17e3220023ca085fadf981932c9347247a9ac794 GIT binary patch literal 20125 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 GApiiQ=Z@U~ literal 0 HcmV?d00001 diff --git a/os/dos/exe2coff/README.licensing b/os/dos/exe2coff/README.licensing new file mode 100644 index 0000000000..112b02a087 --- /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 0000000000..a43ea2126f --- /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 0000000000..8a55047845 --- /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 0000000000..bbe3fe1987 --- /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 0000000000..aa072e8e41 --- /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 0000000000000000000000000000000000000000..5b8db48f0ff3a980a224277ea1c4edc6284818b5 GIT binary patch literal 213612 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

    O(M9Ob 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

    $=+8Ubbs*%PJRKZnk~fwyaxQGG`ek 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[ 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 U=akTtnVc8Kz`(%c^pAl70Bs3}i~s-t literal 0 HcmV?d00001 diff --git a/os/macosx/plistgen.sh b/os/macosx/plistgen.sh new file mode 100755 index 0000000000..b6116d9102 --- /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 0000000000000000000000000000000000000000..e67d10da8c9b1216f69eb3ca24e66a6f1d49ba3a GIT binary patch literal 20053 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 Nc)I$ztaD0e0sz3l>NNlW literal 0 HcmV?d00001 diff --git a/os/morphos/icons/OpenTTD.info b/os/morphos/icons/OpenTTD.info new file mode 100644 index 0000000000000000000000000000000000000000..3a25be683063b654c571d5227b9b691eea11e3ec GIT binary patch literal 7341 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 literal 0 HcmV?d00001 diff --git a/os/morphos/icons/document.info b/os/morphos/icons/document.info new file mode 100644 index 0000000000000000000000000000000000000000..877ea3575f767b3f10d68d4da0a28e559253cd91 GIT binary patch literal 4451 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 CQI^*L literal 0 HcmV?d00001 diff --git a/os/morphos/icons/drawer.info b/os/morphos/icons/drawer.info new file mode 100644 index 0000000000000000000000000000000000000000..149ef7e101f93210509c256b4794f3c3c2fd78fc GIT binary patch literal 5390 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 literal 0 HcmV?d00001 diff --git a/os/os2/build_lang.cmd b/os/os2/build_lang.cmd new file mode 100644 index 0000000000..57d3e9943c --- /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 0000000000..f4eb524995 --- /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 0000000000..39e9843a92 --- /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 0000000000..c2686b456f --- /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 0000000000..0a46dea42a --- /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 0000000000..07ee359dd8 --- /dev/null +++ b/os/os2/installer/make_installer.cmd @@ -0,0 +1,85 @@ +@echo off + +set OPENTTD_VERSION=1.9.3 +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 0000000000..e580e565cf --- /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 0000000000..21c11e80d9 --- /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 0000000000..71465d1677 --- /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 0000000000..361a870e33 --- /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 0000000000..61b2caa553 --- /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 0000000000..cc8836fc0b --- /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 0000000000..56d3572c50 --- /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 0000000000..02d87603c5 --- /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 0000000000..f8d5fb9ed9 --- /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 0000000000..b0a64dfe18 --- /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 0000000000..1c0f55f46c --- /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-2019 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.9.3 +Release: 0 +%define srcver 1.9.3 +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 0000000000..73a2898da2 --- /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 0000000000..45f9602f13 --- /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 0000000000..54c739ad94 --- /dev/null +++ b/os/windows/installer/install.nsi @@ -0,0 +1,744 @@ +# Version numbers to update +!define APPV_MAJOR 1 +!define APPV_MINOR 9 +!define APPV_MAINT 3 +!define APPV_BUILD 0 +!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" + +ManifestDPIAware true +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.md" +!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.md" + 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.md + Push "$INSTDIR\README.md" + 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.md" + 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.md" + !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\gm.cat" "$INSTDIR\baseset\gm.cat" 415 + 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.md" + 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_extra.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.cat" + Delete "$INSTDIR\baseset\gm-tto.cat" + 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\orig_dos.obm" + Delete "$INSTDIR\gm\no_music.obm" + Delete "$INSTDIR\baseset\orig_win.obm" + Delete "$INSTDIR\baseset\orig_dos.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 0000000000000000000000000000000000000000..15a170ec11fa640a3dc7d070c5b34d2138172c43 GIT binary patch literal 25820 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 H|7EWQUNDDjQ-WJh0 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 + + + + Debug + Win32 + + + + basesets + {E12E77CA-C0F1-4ADA-943F-4929274249D3} + basesets + MakeFileProj + + + + Utility + false + v140 + + + + + + + + + ..\src\lang\afrikaans.txt;..\src\lang\arabic_egypt.txt;..\src\lang\basque.txt;..\src\lang\belarusian.txt;..\src\lang\brazilian_portuguese.txt;..\src\lang\bulgarian.txt;..\src\lang\catalan.txt;..\src\lang\croatian.txt;..\src\lang\czech.txt;..\src\lang\danish.txt;..\src\lang\dutch.txt;..\src\lang\english.txt;..\src\lang\english_AU.txt;..\src\lang\english_US.txt;..\src\lang\esperanto.txt;..\src\lang\estonian.txt;..\src\lang\faroese.txt;..\src\lang\finnish.txt;..\src\lang\french.txt;..\src\lang\gaelic.txt;..\src\lang\galician.txt;..\src\lang\german.txt;..\src\lang\greek.txt;..\src\lang\hebrew.txt;..\src\lang\hungarian.txt;..\src\lang\icelandic.txt;..\src\lang\indonesian.txt;..\src\lang\irish.txt;..\src\lang\italian.txt;..\src\lang\japanese.txt;..\src\lang\korean.txt;..\src\lang\latin.txt;..\src\lang\latvian.txt;..\src\lang\lithuanian.txt;..\src\lang\luxembourgish.txt;..\src\lang\malay.txt;..\src\lang\norwegian_bokmal.txt;..\src\lang\norwegian_nynorsk.txt;..\src\lang\polish.txt;..\src\lang\portuguese.txt;..\src\lang\romanian.txt;..\src\lang\russian.txt;..\src\lang\serbian.txt;..\src\lang\simplified_chinese.txt;..\src\lang\slovak.txt;..\src\lang\slovenian.txt;..\src\lang\spanish.txt;..\src\lang\spanish_MX.txt;..\src\lang\swedish.txt;..\src\lang\tamil.txt;..\src\lang\thai.txt;..\src\lang\traditional_chinese.txt;..\src\lang\turkish.txt;..\src\lang\ukrainian.txt;..\src\lang\vietnamese.txt;..\src\lang\welsh.txt + + + ..\bin\baseset\ + ..\objs\baseset\ + + + + Generating no_music.obm baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)no_music.obm" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\no_music.obm;%(Outputs) + + + Generating no_sound.obs baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)no_sound.obs" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\no_sound.obs;%(Outputs) + + + Generating orig_dos.obg baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)orig_dos.obg" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\orig_dos.obg;%(Outputs) + + + Generating orig_dos.obm baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)orig_dos.obm" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\orig_dos.obm;%(Outputs) + + + Generating orig_dos.obs baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)orig_dos.obs" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\orig_dos.obs;%(Outputs) + + + Generating orig_dos_de.obg baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)orig_dos_de.obg" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\orig_dos_de.obg;%(Outputs) + + + Generating orig_tto.obm baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)orig_tto.obm" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\orig_tto.obm;%(Outputs) + + + Generating orig_win.obg baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)orig_win.obg" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\orig_win.obg;%(Outputs) + + + Generating orig_win.obm baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)orig_win.obm" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\orig_win.obm;%(Outputs) + + + Generating orig_win.obs baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)orig_win.obs" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\orig_win.obs;%(Outputs) + + + + + + diff --git a/projects/basesets_vs140.vcxproj.filters b/projects/basesets_vs140.vcxproj.filters new file mode 100644 index 0000000000..aa555f3fc3 --- /dev/null +++ b/projects/basesets_vs140.vcxproj.filters @@ -0,0 +1,40 @@ + + + + + {b5a3ac67-19a9-4276-80e9-2360367d2680} + + + + + Baseset Metadata + + + Baseset Metadata + + + Baseset Metadata + + + Baseset Metadata + + + Baseset Metadata + + + Baseset Metadata + + + Baseset Metadata + + + Baseset Metadata + + + Baseset Metadata + + + Baseset Metadata + + + diff --git a/projects/basesets_vs140.vcxproj.filters.in b/projects/basesets_vs140.vcxproj.filters.in new file mode 100644 index 0000000000..07bff4542f --- /dev/null +++ b/projects/basesets_vs140.vcxproj.filters.in @@ -0,0 +1,11 @@ + + + + + {b5a3ac67-19a9-4276-80e9-2360367d2680} + + + +!!FILES!! + + diff --git a/projects/basesets_vs140.vcxproj.in b/projects/basesets_vs140.vcxproj.in new file mode 100644 index 0000000000..0471100a3e --- /dev/null +++ b/projects/basesets_vs140.vcxproj.in @@ -0,0 +1,40 @@ + + + + + Debug + Win32 + + + + basesets + {E12E77CA-C0F1-4ADA-943F-4929274249D3} + basesets + MakeFileProj + + + + Utility + false + v140 + + + + + + + + +!!FILTERS!! + + + ..\bin\baseset\ + ..\objs\baseset\ + + +!!FILES!! + + + + + diff --git a/projects/basesets_vs141.vcxproj b/projects/basesets_vs141.vcxproj new file mode 100644 index 0000000000..a01f24989b --- /dev/null +++ b/projects/basesets_vs141.vcxproj @@ -0,0 +1,99 @@ + + + + + Debug + Win32 + + + + basesets + {E12E77CA-C0F1-4ADA-943F-4929274249D3} + basesets + MakeFileProj + + + + Utility + false + v141 + + + + + + + + + ..\src\lang\afrikaans.txt;..\src\lang\arabic_egypt.txt;..\src\lang\basque.txt;..\src\lang\belarusian.txt;..\src\lang\brazilian_portuguese.txt;..\src\lang\bulgarian.txt;..\src\lang\catalan.txt;..\src\lang\croatian.txt;..\src\lang\czech.txt;..\src\lang\danish.txt;..\src\lang\dutch.txt;..\src\lang\english.txt;..\src\lang\english_AU.txt;..\src\lang\english_US.txt;..\src\lang\esperanto.txt;..\src\lang\estonian.txt;..\src\lang\faroese.txt;..\src\lang\finnish.txt;..\src\lang\french.txt;..\src\lang\gaelic.txt;..\src\lang\galician.txt;..\src\lang\german.txt;..\src\lang\greek.txt;..\src\lang\hebrew.txt;..\src\lang\hungarian.txt;..\src\lang\icelandic.txt;..\src\lang\indonesian.txt;..\src\lang\irish.txt;..\src\lang\italian.txt;..\src\lang\japanese.txt;..\src\lang\korean.txt;..\src\lang\latin.txt;..\src\lang\latvian.txt;..\src\lang\lithuanian.txt;..\src\lang\luxembourgish.txt;..\src\lang\malay.txt;..\src\lang\norwegian_bokmal.txt;..\src\lang\norwegian_nynorsk.txt;..\src\lang\polish.txt;..\src\lang\portuguese.txt;..\src\lang\romanian.txt;..\src\lang\russian.txt;..\src\lang\serbian.txt;..\src\lang\simplified_chinese.txt;..\src\lang\slovak.txt;..\src\lang\slovenian.txt;..\src\lang\spanish.txt;..\src\lang\spanish_MX.txt;..\src\lang\swedish.txt;..\src\lang\tamil.txt;..\src\lang\thai.txt;..\src\lang\traditional_chinese.txt;..\src\lang\turkish.txt;..\src\lang\ukrainian.txt;..\src\lang\vietnamese.txt;..\src\lang\welsh.txt + + + ..\bin\baseset\ + ..\objs\baseset\ + + + + Generating no_music.obm baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)no_music.obm" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\no_music.obm;%(Outputs) + + + Generating no_sound.obs baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)no_sound.obs" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\no_sound.obs;%(Outputs) + + + Generating orig_dos.obg baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)orig_dos.obg" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\orig_dos.obg;%(Outputs) + + + Generating orig_dos.obm baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)orig_dos.obm" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\orig_dos.obm;%(Outputs) + + + Generating orig_dos.obs baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)orig_dos.obs" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\orig_dos.obs;%(Outputs) + + + Generating orig_dos_de.obg baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)orig_dos_de.obg" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\orig_dos_de.obg;%(Outputs) + + + Generating orig_tto.obm baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)orig_tto.obm" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\orig_tto.obm;%(Outputs) + + + Generating orig_win.obg baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)orig_win.obg" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\orig_win.obg;%(Outputs) + + + Generating orig_win.obm baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)orig_win.obm" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\orig_win.obm;%(Outputs) + + + Generating orig_win.obs baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)orig_win.obs" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\orig_win.obs;%(Outputs) + + + + + + diff --git a/projects/basesets_vs141.vcxproj.filters b/projects/basesets_vs141.vcxproj.filters new file mode 100644 index 0000000000..aa555f3fc3 --- /dev/null +++ b/projects/basesets_vs141.vcxproj.filters @@ -0,0 +1,40 @@ + + + + + {b5a3ac67-19a9-4276-80e9-2360367d2680} + + + + + Baseset Metadata + + + Baseset Metadata + + + Baseset Metadata + + + Baseset Metadata + + + Baseset Metadata + + + Baseset Metadata + + + Baseset Metadata + + + Baseset Metadata + + + Baseset Metadata + + + Baseset Metadata + + + diff --git a/projects/basesets_vs141.vcxproj.filters.in b/projects/basesets_vs141.vcxproj.filters.in new file mode 100644 index 0000000000..07bff4542f --- /dev/null +++ b/projects/basesets_vs141.vcxproj.filters.in @@ -0,0 +1,11 @@ + + + + + {b5a3ac67-19a9-4276-80e9-2360367d2680} + + + +!!FILES!! + + diff --git a/projects/basesets_vs141.vcxproj.in b/projects/basesets_vs141.vcxproj.in new file mode 100644 index 0000000000..69dbd2e078 --- /dev/null +++ b/projects/basesets_vs141.vcxproj.in @@ -0,0 +1,40 @@ + + + + + Debug + Win32 + + + + basesets + {E12E77CA-C0F1-4ADA-943F-4929274249D3} + basesets + MakeFileProj + + + + Utility + false + v141 + + + + + + + + +!!FILTERS!! + + + ..\bin\baseset\ + ..\objs\baseset\ + + +!!FILES!! + + + + + diff --git a/projects/basesets_vs142.vcxproj b/projects/basesets_vs142.vcxproj new file mode 100644 index 0000000000..d483708aa7 --- /dev/null +++ b/projects/basesets_vs142.vcxproj @@ -0,0 +1,99 @@ + + + + + Debug + Win32 + + + + basesets + {E12E77CA-C0F1-4ADA-943F-4929274249D3} + basesets + MakeFileProj + + + + Utility + false + v142 + + + + + + + + + ..\src\lang\afrikaans.txt;..\src\lang\arabic_egypt.txt;..\src\lang\basque.txt;..\src\lang\belarusian.txt;..\src\lang\brazilian_portuguese.txt;..\src\lang\bulgarian.txt;..\src\lang\catalan.txt;..\src\lang\croatian.txt;..\src\lang\czech.txt;..\src\lang\danish.txt;..\src\lang\dutch.txt;..\src\lang\english.txt;..\src\lang\english_AU.txt;..\src\lang\english_US.txt;..\src\lang\esperanto.txt;..\src\lang\estonian.txt;..\src\lang\faroese.txt;..\src\lang\finnish.txt;..\src\lang\french.txt;..\src\lang\gaelic.txt;..\src\lang\galician.txt;..\src\lang\german.txt;..\src\lang\greek.txt;..\src\lang\hebrew.txt;..\src\lang\hungarian.txt;..\src\lang\icelandic.txt;..\src\lang\indonesian.txt;..\src\lang\irish.txt;..\src\lang\italian.txt;..\src\lang\japanese.txt;..\src\lang\korean.txt;..\src\lang\latin.txt;..\src\lang\latvian.txt;..\src\lang\lithuanian.txt;..\src\lang\luxembourgish.txt;..\src\lang\malay.txt;..\src\lang\norwegian_bokmal.txt;..\src\lang\norwegian_nynorsk.txt;..\src\lang\polish.txt;..\src\lang\portuguese.txt;..\src\lang\romanian.txt;..\src\lang\russian.txt;..\src\lang\serbian.txt;..\src\lang\simplified_chinese.txt;..\src\lang\slovak.txt;..\src\lang\slovenian.txt;..\src\lang\spanish.txt;..\src\lang\spanish_MX.txt;..\src\lang\swedish.txt;..\src\lang\tamil.txt;..\src\lang\thai.txt;..\src\lang\traditional_chinese.txt;..\src\lang\turkish.txt;..\src\lang\ukrainian.txt;..\src\lang\vietnamese.txt;..\src\lang\welsh.txt + + + ..\bin\baseset\ + ..\objs\baseset\ + + + + Generating no_music.obm baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)no_music.obm" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\no_music.obm;%(Outputs) + + + Generating no_sound.obs baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)no_sound.obs" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\no_sound.obs;%(Outputs) + + + Generating orig_dos.obg baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)orig_dos.obg" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\orig_dos.obg;%(Outputs) + + + Generating orig_dos.obm baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)orig_dos.obm" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\orig_dos.obm;%(Outputs) + + + Generating orig_dos.obs baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)orig_dos.obs" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\orig_dos.obs;%(Outputs) + + + Generating orig_dos_de.obg baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)orig_dos_de.obg" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\orig_dos_de.obg;%(Outputs) + + + Generating orig_tto.obm baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)orig_tto.obm" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\orig_tto.obm;%(Outputs) + + + Generating orig_win.obg baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)orig_win.obg" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\orig_win.obg;%(Outputs) + + + Generating orig_win.obm baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)orig_win.obm" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\orig_win.obm;%(Outputs) + + + Generating orig_win.obs baseset metadata file + cscript //nologo ..\media\baseset\translations.vbs "%(FullPath)" "$(OutputPath)orig_win.obs" ..\src\lang ..\bin\baseset\orig_extra.grf + $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs) + ..\bin\baseset\orig_win.obs;%(Outputs) + + + + + + diff --git a/projects/basesets_vs142.vcxproj.filters b/projects/basesets_vs142.vcxproj.filters new file mode 100644 index 0000000000..aa555f3fc3 --- /dev/null +++ b/projects/basesets_vs142.vcxproj.filters @@ -0,0 +1,40 @@ + + + + + {b5a3ac67-19a9-4276-80e9-2360367d2680} + + + + + Baseset Metadata + + + Baseset Metadata + + + Baseset Metadata + + + Baseset Metadata + + + Baseset Metadata + + + Baseset Metadata + + + Baseset Metadata + + + Baseset Metadata + + + Baseset Metadata + + + Baseset Metadata + + + diff --git a/projects/basesets_vs142.vcxproj.filters.in b/projects/basesets_vs142.vcxproj.filters.in new file mode 100644 index 0000000000..07bff4542f --- /dev/null +++ b/projects/basesets_vs142.vcxproj.filters.in @@ -0,0 +1,11 @@ + + + + + {b5a3ac67-19a9-4276-80e9-2360367d2680} + + + +!!FILES!! + + diff --git a/projects/basesets_vs142.vcxproj.in b/projects/basesets_vs142.vcxproj.in new file mode 100644 index 0000000000..9743d83e7a --- /dev/null +++ b/projects/basesets_vs142.vcxproj.in @@ -0,0 +1,40 @@ + + + + + Debug + Win32 + + + + basesets + {E12E77CA-C0F1-4ADA-943F-4929274249D3} + basesets + MakeFileProj + + + + Utility + false + v142 + + + + + + + + +!!FILTERS!! + + + ..\bin\baseset\ + ..\objs\baseset\ + + +!!FILES!! + + + + + diff --git a/projects/determineversion.vbs b/projects/determineversion.vbs new file mode 100755 index 0000000000..10b38d35a1 --- /dev/null +++ b/projects/determineversion.vbs @@ -0,0 +1,212 @@ +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, isodate, version, cur_date, githash, istag, isstabletag, filename) + FSO.CopyFile filename & ".in", filename + FindReplaceInFile filename, "!!MODIFIED!!", modified + FindReplaceInFile filename, "!!ISODATE!!", isodate + FindReplaceInFile filename, "!!VERSION!!", version + FindReplaceInFile filename, "!!DATE!!", cur_date + FindReplaceInFile filename, "!!GITHASH!!", githash + FindReplaceInFile filename, "!!ISTAG!!", istag + FindReplaceInFile filename, "!!ISSTABLETAG!!", isstabletag +End Sub + +Sub UpdateFiles(version) + Dim modified, isodate, cur_date, githash, istag, isstabletag + cur_date = DatePart("D", Date) & "." & DatePart("M", Date) & "." & DatePart("YYYY", Date) + + If InStr(version, Chr(9)) Then + ' Split string into field with tails + isodate = Mid(version, InStr(version, Chr(9)) + 1) + modified = Mid(isodate, InStr(isodate, Chr(9)) + 1) + githash = Mid(modified, InStr(modified, Chr(9)) + 1) + istag = Mid(githash, InStr(githash, Chr(9)) + 1) + isstabletag = Mid(istag, InStr(istag, Chr(9)) + 1) + ' Remove tails from fields + version = Mid(version, 1, InStr(version, Chr(9)) - 1) + isodate = Mid(isodate, 1, InStr(isodate, Chr(9)) - 1) + modified = Mid(modified, 1, InStr(modified, Chr(9)) - 1) + githash = Mid(githash, 1, InStr(githash, Chr(9)) - 1) + istag = Mid(istag, 1, InStr(istag, Chr(9)) - 1) + Else + isodate = 0 + modified = 1 + githash = "" + istag = 0 + isstabletag = 0 + End If + + UpdateFile modified, isodate, version, cur_date, githash, istag, isstabletag, "../src/rev.cpp" + UpdateFile modified, isodate, version, cur_date, githash, istag, isstabletag, "../src/os/windows/ottdres.rc" +End Sub + +Function DetermineVersion() + Dim WshShell, branch, tag, modified, isodate, oExec, line, hash, shorthash + Set WshShell = CreateObject("WScript.Shell") + On Error Resume Next + + modified = 0 + hash = "" + shorthash = "" + branch = "" + isodate = "" + tag = "" + + ' Set the environment to english + WshShell.Environment("PROCESS")("LANG") = "en" + + 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() + shorthash = Mid(hash, 1, 10) + ' 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 show -s --pretty=format:%ci") + if Err.Number = 0 Then + isodate = Mid(oExec.StdOut.ReadLine(), 1, 10) + isodate = Replace(isodate, "-", "") + End If ' Err.Number = 0 + + ' Check branch + Err.Clear + Set oExec = WshShell.Exec("git symbolic-ref HEAD") + If Err.Number = 0 Then + line = oExec.StdOut.ReadLine() + branch = Mid(line, InStrRev(line, "/") + 1) + End If ' Err.Number = 0 + + ' 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 + tag = oExec.StdOut.ReadLine() + If Right(tag, 2) = "^0" Then + tag = Left(tag, Len(tag) - 2) + End If + 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 hash = "" And FSO.FileExists("../.ottdrev") Then + Dim rev_file + Set rev_file = FSO.OpenTextFile("../.ottdrev", 1, True, 0) + DetermineVersion = rev_file.ReadLine() + rev_file.Close() + ElseIf hash = "" Then + DetermineVersion = "norev000" + modified = 1 + Else + Dim version, hashprefix, istag, isstabletag + If modified = 0 Then + hashprefix = "-g" + ElseIf modified = 2 Then + hashprefix = "-m" + Else + hashprefix = "-u" + End If + + If tag <> "" Then + version = tag + istag = 1 + + Set stable_regexp = New RegExp + stable_regexp.Pattern = "^[0-9.]*$" + If stable_regexp.Test(tag) Then + isstabletag = 1 + Else + isstabletag = 0 + End If + Else + version = isodate & "-" & branch & hashprefix & shorthash + istag = 0 + isstabletag = 0 + End If + + DetermineVersion = version & Chr(9) & isodate & Chr(9) & modified & Chr(9) & hash & Chr(9) & istag & Chr(9) & isstabletag + 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 = DetermineVersion +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/dpi_aware.manifest b/projects/dpi_aware.manifest new file mode 100644 index 0000000000..ee1c7ea224 --- /dev/null +++ b/projects/dpi_aware.manifest @@ -0,0 +1,29 @@ + + + + + + + + + + + + True/PM + + + + + + + + + + + + + + + + + diff --git a/projects/gen-kdev4.sh b/projects/gen-kdev4.sh new file mode 100755 index 0000000000..4ea5dbc2a8 --- /dev/null +++ b/projects/gen-kdev4.sh @@ -0,0 +1,203 @@ +#!/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 . + +# echo without interpretation of backslash escapes and without +# adding newline at the end - just the string as it is +rawprint() +{ + printf '%s' "$@" +} + +encode_dword() +{ + printf '\x%02x' \ + `expr $1 / 16777216 % 256` \ + `expr $1 / 65536 % 256` \ + `expr $1 / 256 % 256` \ + `expr $1 % 256` +} + +encode_string() +{ + # turn string into UTF-16 and hexdump it + hex_utf16=`rawprint "$1" | iconv -t UTF-16BE | od -t x1 -A n | tr -d -c '[:xdigit:]'`; + + encode_dword `rawprint "$hex_utf16" | wc -m | xargs -I {} expr {} / 2` # length = num hex digits / 2 + rawprint "$hex_utf16" | sed 's/../\\x&/g' # put '\x' prefix before every pair of digits +} + +encode_single_define() +{ + encode_string `rawprint "$1" | grep -o '^[^=]*'` # everything before '=' + rawprint '\x00\x00\x00\n\x00' + encode_string `rawprint "$1" | sed 's/^[^=]*=\?//'` # everything after '=' +} + +# $1 - newline-separated list of defines +encode_defines() +{ + # add some fixed defines and discard empty lines from the tail + defines=`printf 'va_list\nva_args\n%s' "$1"` + + # count lines (no newline at the end so add one) + encode_dword `printf '%s\n' "$defines" | wc -l` + + while [ -n "$defines" ]; do + encode_single_define `rawprint "$defines" | head -n 1` + defines=`rawprint "$defines" | tail -n +2` + done +} + +encode_includes() +{ + encode_dword 3 # number of custom includes + encode_string "$1/src/stdafx.h" + encode_string "$1/objs/lang" + encode_string "$1/objs/setting" +} + +# escape with a backslash (\) characters special to the sed replace string: \ & +# also escape our custom filed separator that we will be using in sed: @ +escape_sed_special() +{ + sed -e 's/[\&@]/\\&/g' +} + + + +PROJECT_DIR=`pwd` +DIR_NAME=`pwd | xargs -0 basename` + +USAGE_TEXT='Usage: + + projects/gen-kdev4 [PROJECT_NAME|-h|--help] + +PROJECT_NAME is the name of the project that will be displayed in KDevelop. +Before executing, cd into OpenTTD folder and run ./configure script. + +-h, --help + print help and exit' + +case "$# $1" in + '1 -h' | '1 --help') printf 'Generate OpenTTD project files for KDevelop 4+\n\n%s\n' "$USAGE_TEXT"; exit 0;; + 1*) PROJECT_NAME="$1";; + 0*) PROJECT_NAME="$DIR_NAME";; + *) printf 'Wrong arguments given. %s\n' "$USAGE_TEXT" >&2; exit 1;; +esac + +CFLAGS=`grep '^using CFLAGS\.\.\.' config.log 2>/dev/null` +if [ -z "$CFLAGS" ]; then + echo "OpenTTD config.log not found" >&2 + echo "cd into OpenTTD first and run 'configure'" >&2 + exit 1 +fi +DEFINES=`eval "printf '%s\n' $CFLAGS" | grep '^\-D' | cut -c3-` + +PROJECT_NAME_SED=s@!!PROJECT_NAME!!@`rawprint "$PROJECT_NAME" | escape_sed_special`@g +PROJECT_DIR_SED=s@!!PROJECT_DIR!!@`rawprint "$PROJECT_DIR" | escape_sed_special`@g +CUSTOM_DEFINES_SED=s@!!CUSTOM_DEFINES!!@`encode_defines "$DEFINES" | escape_sed_special`@g +CUSTOM_INCLUDES_SED=s@!!CUSTOM_INCLUDES!!@`encode_includes "$PROJECT_DIR" | escape_sed_special`@g + +mkdir -p .kdev4 + +sed -e "$PROJECT_NAME_SED" \ + >"$PROJECT_DIR/$DIR_NAME.kdev4" \ + << "EOF" +[Project] +Manager=KDevCustomMakeManager +Name=!!PROJECT_NAME!! +EOF + +sed -e "$PROJECT_DIR_SED" -e "$CUSTOM_DEFINES_SED" -e "$CUSTOM_INCLUDES_SED" \ + >"$PROJECT_DIR/.kdev4/$DIR_NAME.kdev4" \ + << "EOF" +[CustomDefinesAndIncludes][ProjectPath0] +Defines=!!CUSTOM_DEFINES!! +Includes=!!CUSTOM_INCLUDES!! +Path=. + +[Defines And Includes][Compiler] +Name=GCC +Path=gcc +Type=GCC + +[Filters] +size=10 + +[Filters][0] +inclusive=0 +pattern=.* +targets=3 + +[Filters][1] +inclusive=0 +pattern=.svn +targets=2 + +[Filters][2] +inclusive=0 +pattern=.hg +targets=2 + +[Filters][3] +inclusive=0 +pattern=.git +targets=2 + +[Filters][4] +inclusive=0 +pattern=*.rej +targets=1 + +[Filters][5] +inclusive=0 +pattern=*.orig +targets=1 + +[Filters][6] +inclusive=0 +pattern=*~ +targets=1 + +[Filters][7] +inclusive=0 +pattern=.*.kate-swp +targets=1 + +[Filters][8] +inclusive=0 +pattern=.*.swp +targets=1 + +[Filters][9] +inclusive=0 +pattern=/objs +targets=2 + +[Launch] +Launch Configurations=Launch Configuration 0 + +[Launch][Launch Configuration 0] +Configured Launch Modes=execute +Configured Launchers=nativeAppLauncher +Name=Launch OpenTTD\s +Type=Native Application + +[Launch][Launch Configuration 0][Data] +Arguments=-d 1 +Dependencies=@Variant(\x00\x00\x00\t\x00\x00\x00\x00\x00) +Dependency Action=Nothing +EnvironmentGroup= +Executable=file://!!PROJECT_DIR!!/bin/openttd +External Terminal=konsole --noclose --workdir %workdir -e %exe +Project Target= +Use External Terminal=false +Working Directory=file://!!PROJECT_DIR!!/bin +isExecutable=true +EOF diff --git a/projects/generate b/projects/generate new file mode 100755 index 0000000000..cfedc8b32d --- /dev/null +++ b/projects/generate @@ -0,0 +1,334 @@ +#!/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. + +# Set neutral locale so sort behaves the same everywhere +LC_ALL=C +export LC_ALL + +# We really need gawk for this! +AWK=gawk + +${AWK} --version > /dev/null 2> /dev/null +if [ "$?" != "0" ]; then + echo "This script needs gawk to run properly" + exit 1 +fi + +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_vs142.sln is for MSVC 2019 +# openttd_vs142.vcxproj is for MSVC 2019 +# openttd_vs142.vcxproj.filters is for MSVC 2019 +# langs_vs142.vcxproj is for MSVC 2019 +# strgen_vs142.vcxproj is for MSVC 2019 +# strgen_vs142.vcxproj.filters is for MSVC 2019 +# generate_vs142.vcxproj is for MSVC 2019 +# version_vs142.vcxproj is for MSVC 2019 +# basesets_vs142.vcxproj is for MSVC 2019 + +# openttd_vs141.sln is for MSVC 2017 +# openttd_vs141.vcxproj is for MSVC 2017 +# openttd_vs141.vcxproj.filters is for MSVC 2017 +# langs_vs141.vcxproj is for MSVC 2017 +# strgen_vs141.vcxproj is for MSVC 2017 +# strgen_vs141.vcxproj.filters is for MSVC 2017 +# generate_vs141.vcxproj is for MSVC 2017 +# version_vs141.vcxproj is for MSVC 2017 +# basesets_vs141.vcxproj is for MSVC 2017 + +# openttd_vs140.sln is for MSVC 2015 +# openttd_vs140.vcxproj is for MSVC 2015 +# openttd_vs140.vcxproj.filters is for MSVC 2015 +# langs_vs140.vcxproj is for MSVC 2015 +# strgen_vs140.vcxproj is for MSVC 2015 +# strgen_vs140.vcxproj.filters is for MSVC 2015 +# generate_vs140.vcxproj is for MSVC 2015 +# version_vs140.vcxproj is for MSVC 2015 +# basesets_vs140.vcxproj is for MSVC 2015 + + + + +# 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" +enable_fluidsynth="0" +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 | ${AWK} -v BINMODE=1 ' + { gsub("\\r", "", $0); } + /^( *)#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 == "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 == "MSVC" && "'$os'" != "MSVC") { next; } + if ($0 == "DIRECTMUSIC" && "'$enable_directmusic'" != "1") { next; } + if ($0 == "FLUIDSYNTH" && "'$enable_fluidsynth'" != "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); + filter = $0; + print "#3 "; + printf "#3 {c76ff9f1-1e62-46d8-8d55-%012d}\n", i; + print "#3 "; + i += 1; + } + + next; + } + /^$/ { next } + { + if (deep == skip) { + gsub(" ", "", $0); + gsub("/", "\\\\\\\\", $0); + 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 "; + } + } + '`" + + eval "$2=\"\$RES\"" +} + +load_lang_data() { + RES="" + # Windows Folder sort and Linux Folder sort are slightly different. + # By removing the extension and sorting it on Linux, they are the same. + for i in `ls $1 | sed s~.txt$~~g | sort` + do + i=`basename $i` + if [ "$i" == "english" ] + then + continue + fi + RES="$RES +#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 +#2 +#4 +#4 INI +#4 " + RES2="$RES2 ..\\\\src\\\\table\\\\"$i + done + + eval "$2=\"\$RES\$RES2\"" +} + +load_baseset_data() { + FIRST="" + RES="" + RES2=" +#4 " + # Windows Folder sort and Linux Folder sort are slightly different. + # By removing the extension and sorting it on Linux, they are the same. + for i in `ls $2 | sed s~.txt$~~g | sort` + do + if [ "$FIRST" != "" ]; then + RES2="$RES2;" + else + FIRST=1 + fi + i=`basename $i` + RES2="$RES2..\\\\src\\\\lang\\\\$i.txt" + done + RES2="$RES2" + # Windows Folder sort and Linux Folder sort are slightly different. + # By fiddling with the extension and sorting it on Linux, they are the same. + for i in `ls $1 | sed s~\\\.~000~g | sort | sed s~000~.~g` + do + i=`basename $i` + RES="$RES +#2 +#2 Generating "$i" baseset metadata file +#2 cscript //nologo ..\\\\media\\\\baseset\\\\translations.vbs \"%(FullPath)\" \"\$(OutputPath)$i\" ..\\\\src\\\\lang ..\\\\bin\\\\baseset\\\\orig_extra.grf +#2 \$(Langs);..\\\\bin\\\\baseset\\\\orig_extra.grf;%(AdditionalInputs) +#2 ..\\\\bin\\\\baseset\\\\"$i";%(Outputs) +#2 +#3 +#3 Baseset Metadata +#3 " + done + + eval "$3=\"\$RES\$RES2\"" +} + +generate() { + echo "Generating $2..." + # Everything above the !!FILTERS!! marker + cat "$ROOT_DIR/projects/$2".in | ${AWK} -v BINMODE=1 -v FILTERS="$3" -v FILES="$1" ' + { CR = (match($0, "\\r$") > 0 ? "\r" : "") } + /^$/ { next } + /!!FILTERS!!/ { + split(FILTERS, filters, "\n"); + for (i = 1; filters[i] != ""; i++) { + print filters[i] CR; + } + next; + } + /!!FILES!!/ { + split(FILES, files, "\n"); + for (i = 1; files[i] != ""; i++) { + print files[i] CR; + } + next; + } + { + print $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"` + +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"` + +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"` + +load_baseset_data "$ROOT_DIR/media/baseset/*.ob?" "$ROOT_DIR/src/lang/*.txt" baseset +basesetfiles=`echo "$baseset" | grep "^#3" | sed "s-#3--g"` +basesetvcxproj=`echo "$baseset" | grep "^#2" | sed "s~#2~~g"` +basesetlangs=`echo "$baseset" | grep "^#4" | sed "s~#4~~g"` + +generate "$openttdvcxproj" "openttd_vs140.vcxproj" +generate "$openttdfiles" "openttd_vs140.vcxproj.filters" "$openttdfilters" +generate "$openttdvcxproj" "openttd_vs141.vcxproj" +generate "$openttdfiles" "openttd_vs141.vcxproj.filters" "$openttdfilters" +generate "$openttdvcxproj" "openttd_vs142.vcxproj" +generate "$openttdfiles" "openttd_vs142.vcxproj.filters" "$openttdfilters" +generate "$langvcxproj" "langs_vs140.vcxproj" +generate "$langfiles" "langs_vs140.vcxproj.filters" +generate "$langvcxproj" "langs_vs141.vcxproj" +generate "$langfiles" "langs_vs141.vcxproj.filters" +generate "$langvcxproj" "langs_vs142.vcxproj" +generate "$langfiles" "langs_vs142.vcxproj.filters" +generate "$settingsvcxproj" "settings_vs140.vcxproj" "$settingscommand" +generate "$settingsfiles" "settings_vs140.vcxproj.filters" +generate "$settingsvcxproj" "settings_vs141.vcxproj" "$settingscommand" +generate "$settingsfiles" "settings_vs141.vcxproj.filters" +generate "$settingsvcxproj" "settings_vs142.vcxproj" "$settingscommand" +generate "$settingsfiles" "settings_vs142.vcxproj.filters" +generate "$basesetvcxproj" "basesets_vs140.vcxproj" "$basesetlangs" +generate "$basesetfiles" "basesets_vs140.vcxproj.filters" +generate "$basesetvcxproj" "basesets_vs141.vcxproj" "$basesetlangs" +generate "$basesetfiles" "basesets_vs141.vcxproj.filters" +generate "$basesetvcxproj" "basesets_vs142.vcxproj" "$basesetlangs" +generate "$basesetfiles" "basesets_vs142.vcxproj.filters" diff --git a/projects/generate.vbs b/projects/generate.vbs new file mode 100644 index 0000000000..aa91bd3164 --- /dev/null +++ b/projects/generate.vbs @@ -0,0 +1,409 @@ +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_vs142.sln is for MSVC 2019 +' openttd_vs142.vcxproj is for MSVC 2019 +' openttd_vs142.vcxproj.filters is for MSVC 2019 +' langs_vs142.vcxproj is for MSVC 2019 +' strgen_vs142.vcxproj is for MSVC 2019 +' strgen_vs142.vcxproj.filters is for MSVC 2019 +' generate_vs142.vcxproj is for MSVC 2019 +' version_vs142.vcxproj is for MSVC 2019 +' basesets_vs142.vcxproj is for MSVC 2019 + +' openttd_vs141.sln is for MSVC 2017 +' openttd_vs141.vcxproj is for MSVC 2017 +' openttd_vs141.vcxproj.filters is for MSVC 2017 +' langs_vs141.vcxproj is for MSVC 2017 +' strgen_vs141.vcxproj is for MSVC 2017 +' strgen_vs141.vcxproj.filters is for MSVC 2017 +' generate_vs141.vcxproj is for MSVC 2017 +' version_vs141.vcxproj is for MSVC 2017 +' basesets_vs141.vcxproj is for MSVC 2017 + +' openttd_vs140.sln is for MSVC 2015 +' openttd_vs140.vcxproj is for MSVC 2015 +' openttd_vs140.vcxproj.filters is for MSVC 2015 +' langs_vs140.vcxproj is for MSVC 2015 +' strgen_vs140.vcxproj is for MSVC 2015 +' strgen_vs140.vcxproj.filters is for MSVC 2015 +' generate_vs140.vcxproj is for MSVC 2015 +' version_vs140.vcxproj is for MSVC 2015 +' basesets_vs140.vcxproj is for MSVC 2015 + +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 + +Sub load_main_data(filename, ByRef vcxproj, ByRef filters, ByRef files) + Dim file, line, deep, skip, first_filter, first_file, filter, cltype, index + 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 + filters = filters & vbCrLf + Else + first_filter = 1 + End If + filter = line + 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 + 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 + file.Close() +End Sub + +Sub load_lang_data(dir, ByRef vcxproj, ByRef files) + Dim folder, file, first_time + 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 + vcxproj = vcxproj & vbCrLf + files = files & vbCrLf + Else + first_time = 1 + End If + 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 +End Sub + +Sub load_settings_data(dir, ByRef vcxproj, ByRef command, ByRef files) + Dim folder, file, first_time + 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 + vcxproj = vcxproj & vbCrLf + files = files & vbCrLf + Else + first_time = 1 + End If + vcxproj = vcxproj & _ + " " + command = command & " ..\src\table\" & file + files = files & _ + " " & vbCrLf & _ + " INI" & vbCrLf & _ + " " + End If + Next +End Sub + +Sub load_baseset_data(dir, langdir, ByRef vcxproj, ByRef files, ByRef langs) + Dim folder, file, ext, first_time + Set folder = FSO.GetFolder(langdir) + langs = " " + For Each file In folder.Files + If first_time <> 0 Then + langs = langs & ";" + Else + first_time = 1 + End If + file = FSO.GetFileName(file) + ext = FSO.GetExtensionName(file) + langs = langs & "..\src\lang\" & file + Next + langs = langs & "" + first_time = 0 + Set folder = FSO.GetFolder(dir) + For Each file In folder.Files + file = FSO.GetFileName(file) + ext = FSO.GetExtensionName(file) + If ext = "obm" Or ext = "obg" Or ext = "obs" Then + If first_time <> 0 Then + vcxproj = vcxproj & vbCrLf + files = files & vbCrLf + Else + first_time = 1 + End If + vcxproj = vcxproj & _ + " " & vbCrLf & _ + " Generating " & file & " baseset metadata file" & vbCrLf & _ + " cscript //nologo ..\media\baseset\translations.vbs " & Chr(34) & "%(FullPath)" & Chr(34) & " " & Chr(34) & "$(OutputPath)" & file & Chr(34) & " ..\src\lang ..\bin\baseset\orig_extra.grf" & vbCrLf & _ + " $(Langs);..\bin\baseset\orig_extra.grf;%(AdditionalInputs)" & vbCrLf & _ + " ..\bin\baseset\" & file & ";%(Outputs)" & vbCrLf & _ + " " + files = files & _ + " " & vbCrLf & _ + " Baseset Metadata" & vbCrLf & _ + " " + End If + Next +End Sub + +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 openttdvcxproj, openttdfilters, openttdfiles +load_main_data ROOT_DIR & "/source.list", openttdvcxproj, openttdfilters, openttdfiles +generate openttdvcxproj, ROOT_DIR & "/projects/openttd_vs140.vcxproj", Null +generate openttdfiles, ROOT_DIR & "/projects/openttd_vs140.vcxproj.filters", openttdfilters +generate openttdvcxproj, ROOT_DIR & "/projects/openttd_vs141.vcxproj", Null +generate openttdfiles, ROOT_DIR & "/projects/openttd_vs141.vcxproj.filters", openttdfilters +generate openttdvcxproj, ROOT_DIR & "/projects/openttd_vs142.vcxproj", Null +generate openttdfiles, ROOT_DIR & "/projects/openttd_vs142.vcxproj.filters", openttdfilters + +Dim langvcxproj, langfiles +load_lang_data ROOT_DIR & "/src/lang", langvcxproj, langfiles +generate langvcxproj, ROOT_DIR & "/projects/langs_vs140.vcxproj", Null +generate langfiles, ROOT_DIR & "/projects/langs_vs140.vcxproj.filters", Null +generate langvcxproj, ROOT_DIR & "/projects/langs_vs141.vcxproj", Null +generate langfiles, ROOT_DIR & "/projects/langs_vs141.vcxproj.filters", Null +generate langvcxproj, ROOT_DIR & "/projects/langs_vs142.vcxproj", Null +generate langfiles, ROOT_DIR & "/projects/langs_vs142.vcxproj.filters", Null + +Dim settingsvcxproj, settingscommand, settingsfiles +load_settings_data ROOT_DIR & "/src/table", settingsvcxproj, settingscommand, settingsfiles +generate settingsvcxproj, ROOT_DIR & "/projects/settings_vs140.vcxproj", settingscommand +generate settingsfiles, ROOT_DIR & "/projects/settings_vs140.vcxproj.filters", Null +generate settingsvcxproj, ROOT_DIR & "/projects/settings_vs141.vcxproj", settingscommand +generate settingsfiles, ROOT_DIR & "/projects/settings_vs141.vcxproj.filters", Null +generate settingsvcxproj, ROOT_DIR & "/projects/settings_vs142.vcxproj", settingscommand +generate settingsfiles, ROOT_DIR & "/projects/settings_vs142.vcxproj.filters", Null + +Dim basesetvcxproj, basesetfiles, basesetlangs +load_baseset_data ROOT_DIR & "/media/baseset", ROOT_DIR & "/src/lang", basesetvcxproj, basesetfiles, basesetlangs +generate basesetvcxproj, ROOT_DIR & "/projects/basesets_vs140.vcxproj", basesetlangs +generate basesetfiles, ROOT_DIR & "/projects/basesets_vs140.vcxproj.filters", Null +generate basesetvcxproj, ROOT_DIR & "/projects/basesets_vs141.vcxproj", basesetlangs +generate basesetfiles, ROOT_DIR & "/projects/basesets_vs141.vcxproj.filters", Null +generate basesetvcxproj, ROOT_DIR & "/projects/basesets_vs142.vcxproj", basesetlangs +generate basesetfiles, ROOT_DIR & "/projects/basesets_vs142.vcxproj.filters", Null diff --git a/projects/generate_vs140.vcxproj b/projects/generate_vs140.vcxproj new file mode 100644 index 0000000000..b17142050b --- /dev/null +++ b/projects/generate_vs140.vcxproj @@ -0,0 +1,39 @@ + + + + + Debug + Win32 + + + + generate + {2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34} + generate + + + + Utility + v140 + + + + + + + + + + + + + Document + Running %27generate.vbs%27 ... + cscript "$(ProjectDir)generate.vbs" + %(FullPath);%(AdditionalInputs) + + + + + + diff --git a/projects/generate_vs141.vcxproj b/projects/generate_vs141.vcxproj new file mode 100644 index 0000000000..d7a877db17 --- /dev/null +++ b/projects/generate_vs141.vcxproj @@ -0,0 +1,39 @@ + + + + + Debug + Win32 + + + + generate + {2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34} + generate + + + + Utility + v141 + + + + + + + + + + + + + Document + Running %27generate.vbs%27 ... + cscript "$(ProjectDir)generate.vbs" + %(FullPath);%(AdditionalInputs) + + + + + + diff --git a/projects/generate_vs142.vcxproj b/projects/generate_vs142.vcxproj new file mode 100644 index 0000000000..3e55d7a1d4 --- /dev/null +++ b/projects/generate_vs142.vcxproj @@ -0,0 +1,40 @@ + + + + + Debug + Win32 + + + + generate + {2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34} + generate + 8.1 + + + + Utility + v142 + + + + + + + + + + + + + Document + Running %27generate.vbs%27 ... + cscript "$(ProjectDir)generate.vbs" + %(FullPath);%(AdditionalInputs) + + + + + + diff --git a/projects/langs_vs140.vcxproj b/projects/langs_vs140.vcxproj new file mode 100644 index 0000000000..25e7160bfb --- /dev/null +++ b/projects/langs_vs140.vcxproj @@ -0,0 +1,390 @@ + + + + + Debug + Win32 + + + + langs + {0F066B23-18DF-4284-8265-F4A5E7E3B966} + langs + MakeFileProj + + + + Utility + false + v140 + + + + + + + + + + ..\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 spanish_MX 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_MX.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_vs140.vcxproj.filters b/projects/langs_vs140.vcxproj.filters new file mode 100644 index 0000000000..bf5257ec82 --- /dev/null +++ b/projects/langs_vs140.vcxproj.filters @@ -0,0 +1,176 @@ + + + + + {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 + + + Translations + + + diff --git a/projects/langs_vs140.vcxproj.filters.in b/projects/langs_vs140.vcxproj.filters.in new file mode 100644 index 0000000000..0d60ee9595 --- /dev/null +++ b/projects/langs_vs140.vcxproj.filters.in @@ -0,0 +1,12 @@ + + + + + {2a164580-9033-4a01-974b-b21da507efda} + + + + +!!FILES!! + + diff --git a/projects/langs_vs140.vcxproj.in b/projects/langs_vs140.vcxproj.in new file mode 100644 index 0000000000..3271fecffa --- /dev/null +++ b/projects/langs_vs140.vcxproj.in @@ -0,0 +1,61 @@ + + + + + Debug + Win32 + + + + langs + {0F066B23-18DF-4284-8265-F4A5E7E3B966} + langs + MakeFileProj + + + + Utility + false + v140 + + + + + + + + + + ..\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_vs141.vcxproj b/projects/langs_vs141.vcxproj new file mode 100644 index 0000000000..c554c6e378 --- /dev/null +++ b/projects/langs_vs141.vcxproj @@ -0,0 +1,390 @@ + + + + + Debug + Win32 + + + + langs + {0F066B23-18DF-4284-8265-F4A5E7E3B966} + langs + MakeFileProj + + + + Utility + false + v141 + + + + + + + + + + ..\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 spanish_MX 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_MX.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_vs141.vcxproj.filters b/projects/langs_vs141.vcxproj.filters new file mode 100644 index 0000000000..bf5257ec82 --- /dev/null +++ b/projects/langs_vs141.vcxproj.filters @@ -0,0 +1,176 @@ + + + + + {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 + + + Translations + + + diff --git a/projects/langs_vs141.vcxproj.filters.in b/projects/langs_vs141.vcxproj.filters.in new file mode 100644 index 0000000000..0d60ee9595 --- /dev/null +++ b/projects/langs_vs141.vcxproj.filters.in @@ -0,0 +1,12 @@ + + + + + {2a164580-9033-4a01-974b-b21da507efda} + + + + +!!FILES!! + + diff --git a/projects/langs_vs141.vcxproj.in b/projects/langs_vs141.vcxproj.in new file mode 100644 index 0000000000..b73d52c5c9 --- /dev/null +++ b/projects/langs_vs141.vcxproj.in @@ -0,0 +1,61 @@ + + + + + Debug + Win32 + + + + langs + {0F066B23-18DF-4284-8265-F4A5E7E3B966} + langs + MakeFileProj + + + + Utility + false + v141 + + + + + + + + + + ..\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_vs142.vcxproj b/projects/langs_vs142.vcxproj new file mode 100644 index 0000000000..0a11156bb0 --- /dev/null +++ b/projects/langs_vs142.vcxproj @@ -0,0 +1,390 @@ + + + + + Debug + Win32 + + + + langs + {0F066B23-18DF-4284-8265-F4A5E7E3B966} + langs + MakeFileProj + + + + Utility + false + v142 + + + + + + + + + + ..\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 spanish_MX 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_MX.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_vs142.vcxproj.filters b/projects/langs_vs142.vcxproj.filters new file mode 100644 index 0000000000..bf5257ec82 --- /dev/null +++ b/projects/langs_vs142.vcxproj.filters @@ -0,0 +1,176 @@ + + + + + {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 + + + Translations + + + diff --git a/projects/langs_vs142.vcxproj.filters.in b/projects/langs_vs142.vcxproj.filters.in new file mode 100644 index 0000000000..0d60ee9595 --- /dev/null +++ b/projects/langs_vs142.vcxproj.filters.in @@ -0,0 +1,12 @@ + + + + + {2a164580-9033-4a01-974b-b21da507efda} + + + + +!!FILES!! + + diff --git a/projects/langs_vs142.vcxproj.in b/projects/langs_vs142.vcxproj.in new file mode 100644 index 0000000000..f24c7cad78 --- /dev/null +++ b/projects/langs_vs142.vcxproj.in @@ -0,0 +1,61 @@ + + + + + Debug + Win32 + + + + langs + {0F066B23-18DF-4284-8265-F4A5E7E3B966} + langs + MakeFileProj + + + + Utility + false + v142 + + + + + + + + + + ..\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/openttd_vs140.sln b/projects/openttd_vs140.sln new file mode 100644 index 0000000000..e2b7632f7e --- /dev/null +++ b/projects/openttd_vs140.sln @@ -0,0 +1,103 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.23107.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openttd", "openttd_vs140.vcxproj", "{668328A0-B40E-4CDB-BD72-D0064424414A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "strgen", "strgen_vs140.vcxproj", "{A133A442-BD0A-4ADE-B117-AD7545E4BDD1}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "langs", "langs_vs140.vcxproj", "{0F066B23-18DF-4284-8265-F4A5E7E3B966}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "version", "version_vs140.vcxproj", "{1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "generate", "generate_vs140.vcxproj", "{2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "settings", "settings_vs140.vcxproj", "{0817F629-589E-4A3B-B81A-8647BC571E35}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "settingsgen", "settingsgen_vs140.vcxproj", "{E9548DE9-F089-49B7-93A6-30BE2CC311C7}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "regression", "regression_vs140.vcxproj", "{4712B013-437D-42CE-947F-DEBABA15261F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "basesets", "basesets_vs140.vcxproj", "{E12E77CA-C0F1-4ADA-943F-4929274249D3}" +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 + {4712B013-437D-42CE-947F-DEBABA15261F}.Debug|Win32.ActiveCfg = Debug|Win32 + {4712B013-437D-42CE-947F-DEBABA15261F}.Debug|x64.ActiveCfg = Debug|Win32 + {4712B013-437D-42CE-947F-DEBABA15261F}.Release|Win32.ActiveCfg = Debug|Win32 + {4712B013-437D-42CE-947F-DEBABA15261F}.Release|x64.ActiveCfg = Debug|Win32 + {E12E77CA-C0F1-4ADA-943F-4929274249D3}.Debug|Win32.ActiveCfg = Debug|Win32 + {E12E77CA-C0F1-4ADA-943F-4929274249D3}.Debug|Win32.Build.0 = Debug|Win32 + {E12E77CA-C0F1-4ADA-943F-4929274249D3}.Debug|x64.ActiveCfg = Debug|Win32 + {E12E77CA-C0F1-4ADA-943F-4929274249D3}.Debug|x64.Build.0 = Debug|Win32 + {E12E77CA-C0F1-4ADA-943F-4929274249D3}.Release|Win32.ActiveCfg = Debug|Win32 + {E12E77CA-C0F1-4ADA-943F-4929274249D3}.Release|Win32.Build.0 = Debug|Win32 + {E12E77CA-C0F1-4ADA-943F-4929274249D3}.Release|x64.ActiveCfg = Debug|Win32 + {E12E77CA-C0F1-4ADA-943F-4929274249D3}.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_vs140.vcxproj b/projects/openttd_vs140.vcxproj new file mode 100644 index 0000000000..9a741f28df --- /dev/null +++ b/projects/openttd_vs140.vcxproj @@ -0,0 +1,1368 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + openttd + {668328A0-B40E-4CDB-BD72-D0064424414A} + openttd + x86-windows-static + x64-windows-static + + + + Application + false + Unicode + v140 + + + Application + false + Unicode + true + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + true + v140 + + + + + + + + + + + + + + + + + $(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 + + + + + /J /Zc:throwingNew %(AdditionalOptions) + Full + AnySuitable + true + Size + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;WITH_PNG;WITH_FREETYPE;WITH_UNISCRIBE;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 + true + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;%(AdditionalDependencies) + true + %(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + true + false + + + MachineX86 + true + 5.01 + + + os_versions.manifest + PerMonitorHighDPIAware + + + copy "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)..\bin\$(TargetName)$(TargetExt)" + + + + + .\Debug/openttd.tlb + + + + + /J /Zc:throwingNew %(AdditionalOptions) + Disabled + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;WITH_PNG;WITH_FREETYPE;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + $(IntDir) + $(IntDir) + $(IntDir)$(TargetName).pdb + Level3 + false + true + ProgramDatabase + FastCall + Default + true + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;%(AdditionalDependencies) + true + LIBCMT.lib;%(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + false + + + MachineX86 + 5.01 + + + os_versions.manifest + PerMonitorHighDPIAware + + + copy "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)..\bin\$(TargetName)$(TargetExt)" + + + + + X64 + .\Release/openttd.tlb + + + + + /J /Zc:throwingNew %(AdditionalOptions) + Full + AnySuitable + true + Size + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;WITH_PNG;WITH_FREETYPE;WITH_UNISCRIBE;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 + true + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;%(AdditionalDependencies) + true + %(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + true + MachineX64 + true + 5.02 + + + os_versions.manifest + PerMonitorHighDPIAware + + + copy "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)..\bin\$(TargetName)$(TargetExt)" + + + + + X64 + .\Debug/openttd.tlb + + + + + /J /Zc:throwingNew %(AdditionalOptions) + Disabled + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;WITH_PNG;WITH_FREETYPE;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + + + + + $(IntDir) + $(IntDir) + $(IntDir)$(TargetName).pdb + Level3 + false + true + ProgramDatabase + Cdecl + Default + true + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;%(AdditionalDependencies) + true + LIBCMT.lib;%(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + MachineX64 + 5.02 + + + os_versions.manifest + PerMonitorHighDPIAware + + + copy "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)..\bin\$(TargetName)$(TargetExt)" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {0f066b23-18df-4284-8265-f4a5e7e3b966} + false + + + {e9548de9-f089-49b7-93a6-30be2cc311c7} + false + + + {0817f629-589e-4a3b-b81a-8647bc571e35} + false + + + {a133a442-bd0a-4ade-b117-ad7545e4bdd1} + false + + + {1a2b3c5e-1c23-41a5-9c9b-acba2aa75fec} + false + + + {e12e77ca-c0f1-4ada-943f-4929274249d3} + false + + + + diff --git a/projects/openttd_vs140.vcxproj.filters b/projects/openttd_vs140.vcxproj.filters new file mode 100644 index 0000000000..751e54887c --- /dev/null +++ b/projects/openttd_vs140.vcxproj.filters @@ -0,0 +1,3095 @@ + + + + + {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 + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + 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 + + + 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 + + + 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 + + + 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 + + + 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 + + + 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 + + + Music + + + Sound + + + Sound + + + Sound + + + Sound + + + Windows files + + + Windows files + + + Windows files + + + Windows files + + + Threading + + + Threading + + + + + + + diff --git a/projects/openttd_vs140.vcxproj.filters.in b/projects/openttd_vs140.vcxproj.filters.in new file mode 100644 index 0000000000..126bd61459 --- /dev/null +++ b/projects/openttd_vs140.vcxproj.filters.in @@ -0,0 +1,13 @@ + + + +!!FILTERS!! + + +!!FILES!! + + + + + + diff --git a/projects/openttd_vs140.vcxproj.in b/projects/openttd_vs140.vcxproj.in new file mode 100644 index 0000000000..8a9b9a8f97 --- /dev/null +++ b/projects/openttd_vs140.vcxproj.in @@ -0,0 +1,374 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + openttd + {668328A0-B40E-4CDB-BD72-D0064424414A} + openttd + x86-windows-static + x64-windows-static + + + + Application + false + Unicode + v140 + + + Application + false + Unicode + true + v140 + + + Application + false + Unicode + v140 + + + Application + false + Unicode + true + v140 + + + + + + + + + + + + + + + + + $(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 + + + + + /J /Zc:throwingNew %(AdditionalOptions) + Full + AnySuitable + true + Size + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;WITH_PNG;WITH_FREETYPE;WITH_UNISCRIBE;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 + true + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;%(AdditionalDependencies) + true + %(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + true + false + + + MachineX86 + true + 5.01 + + + os_versions.manifest + PerMonitorHighDPIAware + + + copy "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)..\bin\$(TargetName)$(TargetExt)" + + + + + .\Debug/openttd.tlb + + + + + /J /Zc:throwingNew %(AdditionalOptions) + Disabled + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;WITH_PNG;WITH_FREETYPE;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + $(IntDir) + $(IntDir) + $(IntDir)$(TargetName).pdb + Level3 + false + true + ProgramDatabase + FastCall + Default + true + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;%(AdditionalDependencies) + true + LIBCMT.lib;%(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + false + + + MachineX86 + 5.01 + + + os_versions.manifest + PerMonitorHighDPIAware + + + copy "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)..\bin\$(TargetName)$(TargetExt)" + + + + + X64 + .\Release/openttd.tlb + + + + + /J /Zc:throwingNew %(AdditionalOptions) + Full + AnySuitable + true + Size + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;WITH_PNG;WITH_FREETYPE;WITH_UNISCRIBE;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 + true + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;%(AdditionalDependencies) + true + %(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + true + MachineX64 + true + 5.02 + + + os_versions.manifest + PerMonitorHighDPIAware + + + copy "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)..\bin\$(TargetName)$(TargetExt)" + + + + + X64 + .\Debug/openttd.tlb + + + + + /J /Zc:throwingNew %(AdditionalOptions) + Disabled + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;WITH_PNG;WITH_FREETYPE;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + + + + + $(IntDir) + $(IntDir) + $(IntDir)$(TargetName).pdb + Level3 + false + true + ProgramDatabase + Cdecl + Default + true + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;%(AdditionalDependencies) + true + LIBCMT.lib;%(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + MachineX64 + 5.02 + + + os_versions.manifest + PerMonitorHighDPIAware + + + copy "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)..\bin\$(TargetName)$(TargetExt)" + + + +!!FILES!! + + + + + + + + {0f066b23-18df-4284-8265-f4a5e7e3b966} + false + + + {e9548de9-f089-49b7-93a6-30be2cc311c7} + false + + + {0817f629-589e-4a3b-b81a-8647bc571e35} + false + + + {a133a442-bd0a-4ade-b117-ad7545e4bdd1} + false + + + {1a2b3c5e-1c23-41a5-9c9b-acba2aa75fec} + false + + + {e12e77ca-c0f1-4ada-943f-4929274249d3} + false + + + + diff --git a/projects/openttd_vs141.sln b/projects/openttd_vs141.sln new file mode 100644 index 0000000000..6e328ba764 --- /dev/null +++ b/projects/openttd_vs141.sln @@ -0,0 +1,103 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.23107.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openttd", "openttd_vs141.vcxproj", "{668328A0-B40E-4CDB-BD72-D0064424414A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "strgen", "strgen_vs141.vcxproj", "{A133A442-BD0A-4ADE-B117-AD7545E4BDD1}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "langs", "langs_vs141.vcxproj", "{0F066B23-18DF-4284-8265-F4A5E7E3B966}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "version", "version_vs141.vcxproj", "{1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "generate", "generate_vs141.vcxproj", "{2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "settings", "settings_vs141.vcxproj", "{0817F629-589E-4A3B-B81A-8647BC571E35}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "settingsgen", "settingsgen_vs141.vcxproj", "{E9548DE9-F089-49B7-93A6-30BE2CC311C7}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "regression", "regression_vs141.vcxproj", "{4712B013-437D-42CE-947F-DEBABA15261F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "basesets", "basesets_vs141.vcxproj", "{E12E77CA-C0F1-4ADA-943F-4929274249D3}" +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 + {4712B013-437D-42CE-947F-DEBABA15261F}.Debug|Win32.ActiveCfg = Debug|Win32 + {4712B013-437D-42CE-947F-DEBABA15261F}.Debug|x64.ActiveCfg = Debug|Win32 + {4712B013-437D-42CE-947F-DEBABA15261F}.Release|Win32.ActiveCfg = Debug|Win32 + {4712B013-437D-42CE-947F-DEBABA15261F}.Release|x64.ActiveCfg = Debug|Win32 + {E12E77CA-C0F1-4ADA-943F-4929274249D3}.Debug|Win32.ActiveCfg = Debug|Win32 + {E12E77CA-C0F1-4ADA-943F-4929274249D3}.Debug|Win32.Build.0 = Debug|Win32 + {E12E77CA-C0F1-4ADA-943F-4929274249D3}.Debug|x64.ActiveCfg = Debug|Win32 + {E12E77CA-C0F1-4ADA-943F-4929274249D3}.Debug|x64.Build.0 = Debug|Win32 + {E12E77CA-C0F1-4ADA-943F-4929274249D3}.Release|Win32.ActiveCfg = Debug|Win32 + {E12E77CA-C0F1-4ADA-943F-4929274249D3}.Release|Win32.Build.0 = Debug|Win32 + {E12E77CA-C0F1-4ADA-943F-4929274249D3}.Release|x64.ActiveCfg = Debug|Win32 + {E12E77CA-C0F1-4ADA-943F-4929274249D3}.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_vs141.vcxproj b/projects/openttd_vs141.vcxproj new file mode 100644 index 0000000000..2cde5b1d86 --- /dev/null +++ b/projects/openttd_vs141.vcxproj @@ -0,0 +1,1368 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + openttd + {668328A0-B40E-4CDB-BD72-D0064424414A} + openttd + x86-windows-static + x64-windows-static + + + + Application + false + Unicode + v141 + + + Application + false + Unicode + true + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + true + v141 + + + + + + + + + + + + + + + + + $(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 + + + + + /J /Zc:throwingNew /std:c++latest %(AdditionalOptions) + Full + AnySuitable + true + Size + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;WITH_PNG;WITH_FREETYPE;WITH_UNISCRIBE;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 + true + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;%(AdditionalDependencies) + true + %(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + true + false + + + MachineX86 + true + 5.01 + + + os_versions.manifest + PerMonitorHighDPIAware + + + copy "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)..\bin\$(TargetName)$(TargetExt)" + + + + + .\Debug/openttd.tlb + + + + + /J /Zc:throwingNew /std:c++latest %(AdditionalOptions) + Disabled + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;WITH_PNG;WITH_FREETYPE;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + $(IntDir) + $(IntDir) + $(IntDir)$(TargetName).pdb + Level3 + false + true + ProgramDatabase + FastCall + Default + true + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;%(AdditionalDependencies) + true + LIBCMT.lib;%(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + false + + + MachineX86 + 5.01 + + + os_versions.manifest + PerMonitorHighDPIAware + + + copy "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)..\bin\$(TargetName)$(TargetExt)" + + + + + X64 + .\Release/openttd.tlb + + + + + /J /Zc:throwingNew /std:c++latest %(AdditionalOptions) + Full + AnySuitable + true + Size + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;WITH_PNG;WITH_FREETYPE;WITH_UNISCRIBE;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 + true + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;%(AdditionalDependencies) + true + %(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + true + MachineX64 + true + 5.02 + + + os_versions.manifest + PerMonitorHighDPIAware + + + copy "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)..\bin\$(TargetName)$(TargetExt)" + + + + + X64 + .\Debug/openttd.tlb + + + + + /J /Zc:throwingNew /std:c++latest %(AdditionalOptions) + Disabled + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;WITH_PNG;WITH_FREETYPE;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + + + + + $(IntDir) + $(IntDir) + $(IntDir)$(TargetName).pdb + Level3 + false + true + ProgramDatabase + Cdecl + Default + true + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;%(AdditionalDependencies) + true + LIBCMT.lib;%(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + MachineX64 + 5.02 + + + os_versions.manifest + PerMonitorHighDPIAware + + + copy "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)..\bin\$(TargetName)$(TargetExt)" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {0f066b23-18df-4284-8265-f4a5e7e3b966} + false + + + {e9548de9-f089-49b7-93a6-30be2cc311c7} + false + + + {0817f629-589e-4a3b-b81a-8647bc571e35} + false + + + {a133a442-bd0a-4ade-b117-ad7545e4bdd1} + false + + + {1a2b3c5e-1c23-41a5-9c9b-acba2aa75fec} + false + + + {e12e77ca-c0f1-4ada-943f-4929274249d3} + false + + + + diff --git a/projects/openttd_vs141.vcxproj.filters b/projects/openttd_vs141.vcxproj.filters new file mode 100644 index 0000000000..751e54887c --- /dev/null +++ b/projects/openttd_vs141.vcxproj.filters @@ -0,0 +1,3095 @@ + + + + + {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 + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + 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 + + + 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 + + + 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 + + + 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 + + + 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 + + + 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 + + + Music + + + Sound + + + Sound + + + Sound + + + Sound + + + Windows files + + + Windows files + + + Windows files + + + Windows files + + + Threading + + + Threading + + + + + + + diff --git a/projects/openttd_vs141.vcxproj.filters.in b/projects/openttd_vs141.vcxproj.filters.in new file mode 100644 index 0000000000..126bd61459 --- /dev/null +++ b/projects/openttd_vs141.vcxproj.filters.in @@ -0,0 +1,13 @@ + + + +!!FILTERS!! + + +!!FILES!! + + + + + + diff --git a/projects/openttd_vs141.vcxproj.in b/projects/openttd_vs141.vcxproj.in new file mode 100644 index 0000000000..57e153fc7d --- /dev/null +++ b/projects/openttd_vs141.vcxproj.in @@ -0,0 +1,374 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + openttd + {668328A0-B40E-4CDB-BD72-D0064424414A} + openttd + x86-windows-static + x64-windows-static + + + + Application + false + Unicode + v141 + + + Application + false + Unicode + true + v141 + + + Application + false + Unicode + v141 + + + Application + false + Unicode + true + v141 + + + + + + + + + + + + + + + + + $(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 + + + + + /J /Zc:throwingNew /std:c++latest %(AdditionalOptions) + Full + AnySuitable + true + Size + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;WITH_PNG;WITH_FREETYPE;WITH_UNISCRIBE;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 + true + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;%(AdditionalDependencies) + true + %(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + true + false + + + MachineX86 + true + 5.01 + + + os_versions.manifest + PerMonitorHighDPIAware + + + copy "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)..\bin\$(TargetName)$(TargetExt)" + + + + + .\Debug/openttd.tlb + + + + + /J /Zc:throwingNew /std:c++latest %(AdditionalOptions) + Disabled + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;WITH_PNG;WITH_FREETYPE;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + $(IntDir) + $(IntDir) + $(IntDir)$(TargetName).pdb + Level3 + false + true + ProgramDatabase + FastCall + Default + true + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;%(AdditionalDependencies) + true + LIBCMT.lib;%(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + false + + + MachineX86 + 5.01 + + + os_versions.manifest + PerMonitorHighDPIAware + + + copy "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)..\bin\$(TargetName)$(TargetExt)" + + + + + X64 + .\Release/openttd.tlb + + + + + /J /Zc:throwingNew /std:c++latest %(AdditionalOptions) + Full + AnySuitable + true + Size + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;WITH_PNG;WITH_FREETYPE;WITH_UNISCRIBE;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 + true + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;%(AdditionalDependencies) + true + %(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + true + MachineX64 + true + 5.02 + + + os_versions.manifest + PerMonitorHighDPIAware + + + copy "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)..\bin\$(TargetName)$(TargetExt)" + + + + + X64 + .\Debug/openttd.tlb + + + + + /J /Zc:throwingNew /std:c++latest %(AdditionalOptions) + Disabled + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;WITH_PNG;WITH_FREETYPE;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + + + + + $(IntDir) + $(IntDir) + $(IntDir)$(TargetName).pdb + Level3 + false + true + ProgramDatabase + Cdecl + Default + true + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;%(AdditionalDependencies) + true + LIBCMT.lib;%(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + MachineX64 + 5.02 + + + os_versions.manifest + PerMonitorHighDPIAware + + + copy "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)..\bin\$(TargetName)$(TargetExt)" + + + +!!FILES!! + + + + + + + + {0f066b23-18df-4284-8265-f4a5e7e3b966} + false + + + {e9548de9-f089-49b7-93a6-30be2cc311c7} + false + + + {0817f629-589e-4a3b-b81a-8647bc571e35} + false + + + {a133a442-bd0a-4ade-b117-ad7545e4bdd1} + false + + + {1a2b3c5e-1c23-41a5-9c9b-acba2aa75fec} + false + + + {e12e77ca-c0f1-4ada-943f-4929274249d3} + false + + + + diff --git a/projects/openttd_vs142.sln b/projects/openttd_vs142.sln new file mode 100644 index 0000000000..15cd430168 --- /dev/null +++ b/projects/openttd_vs142.sln @@ -0,0 +1,105 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.28516.95 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openttd", "openttd_vs142.vcxproj", "{668328A0-B40E-4CDB-BD72-D0064424414A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "strgen", "strgen_vs142.vcxproj", "{A133A442-BD0A-4ADE-B117-AD7545E4BDD1}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "langs", "langs_vs142.vcxproj", "{0F066B23-18DF-4284-8265-F4A5E7E3B966}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "version", "version_vs142.vcxproj", "{1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "generate", "generate_vs142.vcxproj", "{2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "settings", "settings_vs142.vcxproj", "{0817F629-589E-4A3B-B81A-8647BC571E35}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "settingsgen", "settingsgen_vs142.vcxproj", "{E9548DE9-F089-49B7-93A6-30BE2CC311C7}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "regression", "regression_vs142.vcxproj", "{4712B013-437D-42CE-947F-DEBABA15261F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "basesets", "basesets_vs142.vcxproj", "{E12E77CA-C0F1-4ADA-943F-4929274249D3}" +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 + {4712B013-437D-42CE-947F-DEBABA15261F}.Debug|Win32.ActiveCfg = Debug|Win32 + {4712B013-437D-42CE-947F-DEBABA15261F}.Debug|x64.ActiveCfg = Debug|Win32 + {4712B013-437D-42CE-947F-DEBABA15261F}.Release|Win32.ActiveCfg = Debug|Win32 + {4712B013-437D-42CE-947F-DEBABA15261F}.Release|x64.ActiveCfg = Debug|Win32 + {E12E77CA-C0F1-4ADA-943F-4929274249D3}.Debug|Win32.ActiveCfg = Debug|Win32 + {E12E77CA-C0F1-4ADA-943F-4929274249D3}.Debug|Win32.Build.0 = Debug|Win32 + {E12E77CA-C0F1-4ADA-943F-4929274249D3}.Debug|x64.ActiveCfg = Debug|Win32 + {E12E77CA-C0F1-4ADA-943F-4929274249D3}.Debug|x64.Build.0 = Debug|Win32 + {E12E77CA-C0F1-4ADA-943F-4929274249D3}.Release|Win32.ActiveCfg = Debug|Win32 + {E12E77CA-C0F1-4ADA-943F-4929274249D3}.Release|Win32.Build.0 = Debug|Win32 + {E12E77CA-C0F1-4ADA-943F-4929274249D3}.Release|x64.ActiveCfg = Debug|Win32 + {E12E77CA-C0F1-4ADA-943F-4929274249D3}.Release|x64.Build.0 = Debug|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1DE4D2BD-DBC4-4304-907E-34994EEAA4C1} + EndGlobalSection + GlobalSection(DPCodeReviewSolutionGUID) = preSolution + DPCodeReviewSolutionGUID = {00000000-0000-0000-0000-000000000000} + EndGlobalSection +EndGlobal diff --git a/projects/openttd_vs142.vcxproj b/projects/openttd_vs142.vcxproj new file mode 100644 index 0000000000..5999d00d6c --- /dev/null +++ b/projects/openttd_vs142.vcxproj @@ -0,0 +1,1368 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + openttd + {668328A0-B40E-4CDB-BD72-D0064424414A} + openttd + x86-windows-static + x64-windows-static + + + + Application + false + Unicode + v142 + + + Application + false + Unicode + true + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + true + v142 + + + + + + + + + + + + + + + + + $(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 + + + + + /J /Zc:throwingNew /std:c++latest %(AdditionalOptions) + Full + AnySuitable + true + Size + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;WITH_PNG;WITH_FREETYPE;WITH_UNISCRIBE;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 + true + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;%(AdditionalDependencies) + true + %(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + true + false + + + MachineX86 + true + 5.01 + + + os_versions.manifest + PerMonitorHighDPIAware + + + copy "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)..\bin\$(TargetName)$(TargetExt)" + + + + + .\Debug/openttd.tlb + + + + + /J /Zc:throwingNew /std:c++latest %(AdditionalOptions) + Disabled + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;WITH_PNG;WITH_FREETYPE;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + $(IntDir) + $(IntDir) + $(IntDir)$(TargetName).pdb + Level3 + false + true + ProgramDatabase + FastCall + Default + true + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;%(AdditionalDependencies) + true + LIBCMT.lib;%(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + false + + + MachineX86 + 5.01 + + + os_versions.manifest + PerMonitorHighDPIAware + + + copy "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)..\bin\$(TargetName)$(TargetExt)" + + + + + X64 + .\Release/openttd.tlb + + + + + /J /Zc:throwingNew /std:c++latest %(AdditionalOptions) + Full + AnySuitable + true + Size + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;WITH_PNG;WITH_FREETYPE;WITH_UNISCRIBE;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 + true + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;%(AdditionalDependencies) + true + %(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + true + MachineX64 + true + 5.02 + + + os_versions.manifest + PerMonitorHighDPIAware + + + copy "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)..\bin\$(TargetName)$(TargetExt)" + + + + + X64 + .\Debug/openttd.tlb + + + + + /J /Zc:throwingNew /std:c++latest %(AdditionalOptions) + Disabled + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;WITH_PNG;WITH_FREETYPE;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + + + + + $(IntDir) + $(IntDir) + $(IntDir)$(TargetName).pdb + Level3 + false + true + ProgramDatabase + Cdecl + Default + true + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;%(AdditionalDependencies) + true + LIBCMT.lib;%(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + MachineX64 + 5.02 + + + os_versions.manifest + PerMonitorHighDPIAware + + + copy "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)..\bin\$(TargetName)$(TargetExt)" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {0f066b23-18df-4284-8265-f4a5e7e3b966} + false + + + {e9548de9-f089-49b7-93a6-30be2cc311c7} + false + + + {0817f629-589e-4a3b-b81a-8647bc571e35} + false + + + {a133a442-bd0a-4ade-b117-ad7545e4bdd1} + false + + + {1a2b3c5e-1c23-41a5-9c9b-acba2aa75fec} + false + + + {e12e77ca-c0f1-4ada-943f-4929274249d3} + false + + + + diff --git a/projects/openttd_vs142.vcxproj.filters b/projects/openttd_vs142.vcxproj.filters new file mode 100644 index 0000000000..751e54887c --- /dev/null +++ b/projects/openttd_vs142.vcxproj.filters @@ -0,0 +1,3095 @@ + + + + + {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 + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + 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 + + + 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 + + + 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 + + + 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 + + + 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 + + + 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 + + + Music + + + Sound + + + Sound + + + Sound + + + Sound + + + Windows files + + + Windows files + + + Windows files + + + Windows files + + + Threading + + + Threading + + + + + + + diff --git a/projects/openttd_vs142.vcxproj.filters.in b/projects/openttd_vs142.vcxproj.filters.in new file mode 100644 index 0000000000..126bd61459 --- /dev/null +++ b/projects/openttd_vs142.vcxproj.filters.in @@ -0,0 +1,13 @@ + + + +!!FILTERS!! + + +!!FILES!! + + + + + + diff --git a/projects/openttd_vs142.vcxproj.in b/projects/openttd_vs142.vcxproj.in new file mode 100644 index 0000000000..7176fea58a --- /dev/null +++ b/projects/openttd_vs142.vcxproj.in @@ -0,0 +1,374 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + openttd + {668328A0-B40E-4CDB-BD72-D0064424414A} + openttd + x86-windows-static + x64-windows-static + + + + Application + false + Unicode + v142 + + + Application + false + Unicode + true + v142 + + + Application + false + Unicode + v142 + + + Application + false + Unicode + true + v142 + + + + + + + + + + + + + + + + + $(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 + + + + + /J /Zc:throwingNew /std:c++latest %(AdditionalOptions) + Full + AnySuitable + true + Size + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;WITH_PNG;WITH_FREETYPE;WITH_UNISCRIBE;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 + true + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;%(AdditionalDependencies) + true + %(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + true + false + + + MachineX86 + true + 5.01 + + + os_versions.manifest + PerMonitorHighDPIAware + + + copy "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)..\bin\$(TargetName)$(TargetExt)" + + + + + .\Debug/openttd.tlb + + + + + /J /Zc:throwingNew /std:c++latest %(AdditionalOptions) + Disabled + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;WITH_PNG;WITH_FREETYPE;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + $(IntDir) + $(IntDir) + $(IntDir)$(TargetName).pdb + Level3 + false + true + ProgramDatabase + FastCall + Default + true + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;%(AdditionalDependencies) + true + LIBCMT.lib;%(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + false + + + MachineX86 + 5.01 + + + os_versions.manifest + PerMonitorHighDPIAware + + + copy "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)..\bin\$(TargetName)$(TargetExt)" + + + + + X64 + .\Release/openttd.tlb + + + + + /J /Zc:throwingNew /std:c++latest %(AdditionalOptions) + Full + AnySuitable + true + Size + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;WITH_PNG;WITH_FREETYPE;WITH_UNISCRIBE;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 + true + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;%(AdditionalDependencies) + true + %(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + true + MachineX64 + true + 5.02 + + + os_versions.manifest + PerMonitorHighDPIAware + + + copy "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)..\bin\$(TargetName)$(TargetExt)" + + + + + X64 + .\Debug/openttd.tlb + + + + + /J /Zc:throwingNew /std:c++latest %(AdditionalOptions) + Disabled + true + ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) + _DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;WITH_PNG;WITH_FREETYPE;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + + + + + $(IntDir) + $(IntDir) + $(IntDir)$(TargetName).pdb + Level3 + false + true + ProgramDatabase + Cdecl + Default + true + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0809 + + + winmm.lib;ws2_32.lib;imm32.lib;%(AdditionalDependencies) + true + LIBCMT.lib;%(IgnoreSpecificDefaultLibraries) + true + Windows + 1048576 + 1048576 + MachineX64 + 5.02 + + + os_versions.manifest + PerMonitorHighDPIAware + + + copy "$(OutDir)$(TargetName)$(TargetExt)" "$(SolutionDir)..\bin\$(TargetName)$(TargetExt)" + + + +!!FILES!! + + + + + + + + {0f066b23-18df-4284-8265-f4a5e7e3b966} + false + + + {e9548de9-f089-49b7-93a6-30be2cc311c7} + false + + + {0817f629-589e-4a3b-b81a-8647bc571e35} + false + + + {a133a442-bd0a-4ade-b117-ad7545e4bdd1} + false + + + {1a2b3c5e-1c23-41a5-9c9b-acba2aa75fec} + false + + + {e12e77ca-c0f1-4ada-943f-4929274249d3} + false + + + + diff --git a/projects/os_versions.manifest b/projects/os_versions.manifest new file mode 100644 index 0000000000..c7905ee709 --- /dev/null +++ b/projects/os_versions.manifest @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/projects/regression.bat b/projects/regression.bat new file mode 100644 index 0000000000..db373c371b --- /dev/null +++ b/projects/regression.bat @@ -0,0 +1,6 @@ +cd ..\bin +editbin /nologo /subsystem:console openttd.exe +cscript /nologo ai\regression\run.vbs +set RESULT=%ERRORLEVEL% +editbin /nologo /subsystem:windows openttd.exe +exit %RESULT% diff --git a/projects/regression_vs140.vcxproj b/projects/regression_vs140.vcxproj new file mode 100644 index 0000000000..b1c9f4930a --- /dev/null +++ b/projects/regression_vs140.vcxproj @@ -0,0 +1,41 @@ + + + + + Debug + Win32 + + + + {4712B013-437D-42CE-947F-DEBABA15261F} + regression + regression + + + + Makefile + v140 + + + + + + + + + + + + call regression.bat + call regression.bat + del ..\bin\tmp.regression + + + + {668328a0-b40e-4cdb-bd72-d0064424414a} + + + + + + diff --git a/projects/regression_vs141.vcxproj b/projects/regression_vs141.vcxproj new file mode 100644 index 0000000000..fda3f3312d --- /dev/null +++ b/projects/regression_vs141.vcxproj @@ -0,0 +1,41 @@ + + + + + Debug + Win32 + + + + {4712B013-437D-42CE-947F-DEBABA15261F} + regression + regression + + + + Makefile + v141 + + + + + + + + + + + + call regression.bat + call regression.bat + del ..\bin\tmp.regression + + + + {668328a0-b40e-4cdb-bd72-d0064424414a} + + + + + + diff --git a/projects/regression_vs142.vcxproj b/projects/regression_vs142.vcxproj new file mode 100644 index 0000000000..3ddcc6f37a --- /dev/null +++ b/projects/regression_vs142.vcxproj @@ -0,0 +1,41 @@ + + + + + Debug + Win32 + + + + {4712B013-437D-42CE-947F-DEBABA15261F} + regression + regression + + + + Makefile + v142 + + + + + + + + + + + + call regression.bat + call regression.bat + del ..\bin\tmp.regression + + + + {668328a0-b40e-4cdb-bd72-d0064424414a} + + + + + + diff --git a/projects/settings_vs140.vcxproj b/projects/settings_vs140.vcxproj new file mode 100644 index 0000000000..9952df47bb --- /dev/null +++ b/projects/settings_vs140.vcxproj @@ -0,0 +1,60 @@ + + + + + Debug + Win32 + + + + settings + {0817F629-589E-4A3B-B81A-8647BC571E35} + settings + + + + Makefile + v140 + + + + + + + + + +..\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 + + + + ..\objs\settings\table\ + ..\objs\settings\table\ + $(SettingsCommandLine) + $(SettingsCommandLine) + del ..\objs\settings\table\settings.h + ..\objs\settings\table\settings.h + + + + + + + + + + + + + + + + + {e9548de9-f089-49b7-93a6-30be2cc311c7} + false + + + + + + diff --git a/projects/settings_vs140.vcxproj.filters b/projects/settings_vs140.vcxproj.filters new file mode 100644 index 0000000000..8caf9fa0a6 --- /dev/null +++ b/projects/settings_vs140.vcxproj.filters @@ -0,0 +1,35 @@ + + + + + {21deca6c-8df4-4f34-9dad-17d7781cd5a0} + + + + + INI + + + INI + + + INI + + + INI + + + INI + + + INI + + + INI + + + + + + + diff --git a/projects/settings_vs140.vcxproj.filters.in b/projects/settings_vs140.vcxproj.filters.in new file mode 100644 index 0000000000..08f90670d2 --- /dev/null +++ b/projects/settings_vs140.vcxproj.filters.in @@ -0,0 +1,15 @@ + + + + + {21deca6c-8df4-4f34-9dad-17d7781cd5a0} + + + +!!FILES!! + + + + + + diff --git a/projects/settings_vs140.vcxproj.in b/projects/settings_vs140.vcxproj.in new file mode 100644 index 0000000000..9bb0cc7f0b --- /dev/null +++ b/projects/settings_vs140.vcxproj.in @@ -0,0 +1,54 @@ + + + + + Debug + Win32 + + + + settings + {0817F629-589E-4A3B-B81A-8647BC571E35} + settings + + + + Makefile + v140 + + + + + + + + + +!!FILTERS!! + + + + ..\objs\settings\table\ + ..\objs\settings\table\ + $(SettingsCommandLine) + $(SettingsCommandLine) + del ..\objs\settings\table\settings.h + ..\objs\settings\table\settings.h + + +!!FILES!! + + + + + + + + {e9548de9-f089-49b7-93a6-30be2cc311c7} + false + + + + + + diff --git a/projects/settings_vs141.vcxproj b/projects/settings_vs141.vcxproj new file mode 100644 index 0000000000..9c20f1407e --- /dev/null +++ b/projects/settings_vs141.vcxproj @@ -0,0 +1,60 @@ + + + + + Debug + Win32 + + + + settings + {0817F629-589E-4A3B-B81A-8647BC571E35} + settings + + + + Makefile + v141 + + + + + + + + + +..\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 + + + + ..\objs\settings\table\ + ..\objs\settings\table\ + $(SettingsCommandLine) + $(SettingsCommandLine) + del ..\objs\settings\table\settings.h + ..\objs\settings\table\settings.h + + + + + + + + + + + + + + + + + {e9548de9-f089-49b7-93a6-30be2cc311c7} + false + + + + + + diff --git a/projects/settings_vs141.vcxproj.filters b/projects/settings_vs141.vcxproj.filters new file mode 100644 index 0000000000..8caf9fa0a6 --- /dev/null +++ b/projects/settings_vs141.vcxproj.filters @@ -0,0 +1,35 @@ + + + + + {21deca6c-8df4-4f34-9dad-17d7781cd5a0} + + + + + INI + + + INI + + + INI + + + INI + + + INI + + + INI + + + INI + + + + + + + diff --git a/projects/settings_vs141.vcxproj.filters.in b/projects/settings_vs141.vcxproj.filters.in new file mode 100644 index 0000000000..08f90670d2 --- /dev/null +++ b/projects/settings_vs141.vcxproj.filters.in @@ -0,0 +1,15 @@ + + + + + {21deca6c-8df4-4f34-9dad-17d7781cd5a0} + + + +!!FILES!! + + + + + + diff --git a/projects/settings_vs141.vcxproj.in b/projects/settings_vs141.vcxproj.in new file mode 100644 index 0000000000..23e044cc17 --- /dev/null +++ b/projects/settings_vs141.vcxproj.in @@ -0,0 +1,54 @@ + + + + + Debug + Win32 + + + + settings + {0817F629-589E-4A3B-B81A-8647BC571E35} + settings + + + + Makefile + v141 + + + + + + + + + +!!FILTERS!! + + + + ..\objs\settings\table\ + ..\objs\settings\table\ + $(SettingsCommandLine) + $(SettingsCommandLine) + del ..\objs\settings\table\settings.h + ..\objs\settings\table\settings.h + + +!!FILES!! + + + + + + + + {e9548de9-f089-49b7-93a6-30be2cc311c7} + false + + + + + + diff --git a/projects/settings_vs142.vcxproj b/projects/settings_vs142.vcxproj new file mode 100644 index 0000000000..a2dda134b5 --- /dev/null +++ b/projects/settings_vs142.vcxproj @@ -0,0 +1,60 @@ + + + + + Debug + Win32 + + + + settings + {0817F629-589E-4A3B-B81A-8647BC571E35} + settings + + + + Makefile + v142 + + + + + + + + + +..\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 + + + + ..\objs\settings\table\ + ..\objs\settings\table\ + $(SettingsCommandLine) + $(SettingsCommandLine) + del ..\objs\settings\table\settings.h + ..\objs\settings\table\settings.h + + + + + + + + + + + + + + + + + {e9548de9-f089-49b7-93a6-30be2cc311c7} + false + + + + + + diff --git a/projects/settings_vs142.vcxproj.filters b/projects/settings_vs142.vcxproj.filters new file mode 100644 index 0000000000..8caf9fa0a6 --- /dev/null +++ b/projects/settings_vs142.vcxproj.filters @@ -0,0 +1,35 @@ + + + + + {21deca6c-8df4-4f34-9dad-17d7781cd5a0} + + + + + INI + + + INI + + + INI + + + INI + + + INI + + + INI + + + INI + + + + + + + diff --git a/projects/settings_vs142.vcxproj.filters.in b/projects/settings_vs142.vcxproj.filters.in new file mode 100644 index 0000000000..08f90670d2 --- /dev/null +++ b/projects/settings_vs142.vcxproj.filters.in @@ -0,0 +1,15 @@ + + + + + {21deca6c-8df4-4f34-9dad-17d7781cd5a0} + + + +!!FILES!! + + + + + + diff --git a/projects/settings_vs142.vcxproj.in b/projects/settings_vs142.vcxproj.in new file mode 100644 index 0000000000..3e49b7ca02 --- /dev/null +++ b/projects/settings_vs142.vcxproj.in @@ -0,0 +1,54 @@ + + + + + Debug + Win32 + + + + settings + {0817F629-589E-4A3B-B81A-8647BC571E35} + settings + + + + Makefile + v142 + + + + + + + + + +!!FILTERS!! + + + + ..\objs\settings\table\ + ..\objs\settings\table\ + $(SettingsCommandLine) + $(SettingsCommandLine) + del ..\objs\settings\table\settings.h + ..\objs\settings\table\settings.h + + +!!FILES!! + + + + + + + + {e9548de9-f089-49b7-93a6-30be2cc311c7} + false + + + + + + diff --git a/projects/settingsgen_vs140.vcxproj b/projects/settingsgen_vs140.vcxproj new file mode 100644 index 0000000000..12ce280f3a --- /dev/null +++ b/projects/settingsgen_vs140.vcxproj @@ -0,0 +1,83 @@ + + + + + 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 + true + ProgramDatabase + MultiThreadedDebug + + + $(OutDir)settings_gen.exe + true + false + + + Console + 5.01 + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/settingsgen_vs140.vcxproj.filters b/projects/settingsgen_vs140.vcxproj.filters new file mode 100644 index 0000000000..c8afe0c8ed --- /dev/null +++ b/projects/settingsgen_vs140.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_vs141.vcxproj b/projects/settingsgen_vs141.vcxproj new file mode 100644 index 0000000000..2b356f2eab --- /dev/null +++ b/projects/settingsgen_vs141.vcxproj @@ -0,0 +1,83 @@ + + + + + Debug + Win32 + + + + settingsgen + {E9548DE9-F089-49B7-93A6-30BE2CC311C7} + settings + + + + Application + MultiByte + v141 + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\objs\settings\ + ..\objs\settings\ + settings_gen + + + + + + + + %(Inputs) + + + MinSpace + Size + SETTINGSGEN;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + All + $(IntDir)$(TargetName).pdb + Level3 + true + ProgramDatabase + MultiThreadedDebug + + + $(OutDir)settings_gen.exe + true + false + + + Console + 5.01 + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/settingsgen_vs141.vcxproj.filters b/projects/settingsgen_vs141.vcxproj.filters new file mode 100644 index 0000000000..c8afe0c8ed --- /dev/null +++ b/projects/settingsgen_vs141.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_vs142.vcxproj b/projects/settingsgen_vs142.vcxproj new file mode 100644 index 0000000000..ca0418c15c --- /dev/null +++ b/projects/settingsgen_vs142.vcxproj @@ -0,0 +1,84 @@ + + + + + Debug + Win32 + + + + settingsgen + {E9548DE9-F089-49B7-93A6-30BE2CC311C7} + settings + 8.1 + + + + Application + MultiByte + v142 + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\objs\settings\ + ..\objs\settings\ + settings_gen + + + + + + + + %(Inputs) + + + MinSpace + Size + SETTINGSGEN;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + All + $(IntDir)$(TargetName).pdb + Level3 + true + ProgramDatabase + MultiThreadedDebug + + + $(OutDir)settings_gen.exe + true + false + + + Console + 5.01 + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/settingsgen_vs142.vcxproj.filters b/projects/settingsgen_vs142.vcxproj.filters new file mode 100644 index 0000000000..c8afe0c8ed --- /dev/null +++ b/projects/settingsgen_vs142.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/strgen_vs140.vcxproj b/projects/strgen_vs140.vcxproj new file mode 100644 index 0000000000..b972d873eb --- /dev/null +++ b/projects/strgen_vs140.vcxproj @@ -0,0 +1,95 @@ + + + + + Debug + Win32 + + + + strgen + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1} + strgen + + + + Application + false + MultiByte + v140 + + + + + + + + + + $(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 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x041d + + + true + true + $(IntDir)strgen.pdb + Console + false + + + MachineX86 + 5.01 + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/strgen_vs140.vcxproj.filters b/projects/strgen_vs140.vcxproj.filters new file mode 100644 index 0000000000..58864ee691 --- /dev/null +++ b/projects/strgen_vs140.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_vs141.vcxproj b/projects/strgen_vs141.vcxproj new file mode 100644 index 0000000000..addc6f10a5 --- /dev/null +++ b/projects/strgen_vs141.vcxproj @@ -0,0 +1,95 @@ + + + + + Debug + Win32 + + + + strgen + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1} + strgen + + + + Application + false + MultiByte + v141 + + + + + + + + + + $(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 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x041d + + + true + true + $(IntDir)strgen.pdb + Console + false + + + MachineX86 + 5.01 + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/strgen_vs141.vcxproj.filters b/projects/strgen_vs141.vcxproj.filters new file mode 100644 index 0000000000..58864ee691 --- /dev/null +++ b/projects/strgen_vs141.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_vs142.vcxproj b/projects/strgen_vs142.vcxproj new file mode 100644 index 0000000000..5329d68daa --- /dev/null +++ b/projects/strgen_vs142.vcxproj @@ -0,0 +1,96 @@ + + + + + Debug + Win32 + + + + strgen + {A133A442-BD0A-4ADE-B117-AD7545E4BDD1} + strgen + 8.1 + + + + Application + false + MultiByte + v142 + + + + + + + + + + $(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 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x041d + + + true + true + $(IntDir)strgen.pdb + Console + false + + + MachineX86 + 5.01 + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/strgen_vs142.vcxproj.filters b/projects/strgen_vs142.vcxproj.filters new file mode 100644 index 0000000000..58864ee691 --- /dev/null +++ b/projects/strgen_vs142.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/version_vs140.vcxproj b/projects/version_vs140.vcxproj new file mode 100644 index 0000000000..6e71a88201 --- /dev/null +++ b/projects/version_vs140.vcxproj @@ -0,0 +1,42 @@ + + + + + Debug + Win32 + + + + version + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC} + version + + + + Makefile + MultiByte + v140 + + + + + + + + + + $(SolutionDir)..\objs\version\ + $(SolutionDir)..\objs\version\ + cscript "$(ProjectDir)/determineversion.vbs" + cscript "$(ProjectDir)/determineversion.vbs" + ..\src\rev.cpp + del ..\src\rev.cpp + + + + + + + + + diff --git a/projects/version_vs141.vcxproj b/projects/version_vs141.vcxproj new file mode 100644 index 0000000000..5d8ee8c74f --- /dev/null +++ b/projects/version_vs141.vcxproj @@ -0,0 +1,42 @@ + + + + + Debug + Win32 + + + + version + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC} + version + + + + Makefile + MultiByte + v141 + + + + + + + + + + $(SolutionDir)..\objs\version\ + $(SolutionDir)..\objs\version\ + cscript "$(ProjectDir)/determineversion.vbs" + cscript "$(ProjectDir)/determineversion.vbs" + ..\src\rev.cpp + del ..\src\rev.cpp + + + + + + + + + diff --git a/projects/version_vs142.vcxproj b/projects/version_vs142.vcxproj new file mode 100644 index 0000000000..31971e35c9 --- /dev/null +++ b/projects/version_vs142.vcxproj @@ -0,0 +1,42 @@ + + + + + Debug + Win32 + + + + version + {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC} + version + + + + Makefile + MultiByte + v142 + + + + + + + + + + $(SolutionDir)..\objs\version\ + $(SolutionDir)..\objs\version\ + cscript "$(ProjectDir)/determineversion.vbs" + cscript "$(ProjectDir)/determineversion.vbs" + ..\src\rev.cpp + del ..\src\rev.cpp + + + + + + + + + diff --git a/source.list b/source.list new file mode 100644 index 0000000000..ce6c4cf150 --- /dev/null +++ b/source.list @@ -0,0 +1,1198 @@ +# 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 +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 +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 +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 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 +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 +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 +framerate_type.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 +guitimer_func.h +heightmap.h +highscore.h +hotkeys.h +house.h +house_type.h +industry.h +industry_type.h +industrytype.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/midi.h +music/midifile.hpp +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 +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 +os/windows/string_uniscribe.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 +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 +sound/xaudio2_s.h +zoom_func.h +zoom_type.h +#if WIN32 +#else +music/bemidi.h +music/cocoa_m.h +music/extmidi.h +music/libtimidity.h +music/fluidsynth.h +music/os2_m.h +music/qtmidi.h +os/macosx/macos.h +os/macosx/osx_stdafx.h +os/macosx/splash.h +os/macosx/string_osx.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 +depot_gui.cpp +dock_gui.cpp +engine_gui.cpp +error_gui.cpp +fios_gui.cpp +framerate_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 +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/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/framerate_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 +table/string_colours.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_client.hpp +script/api/script_clientlist.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_client.cpp +script/api/script_clientlist.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_sse2.cpp +blitter/32bpp_anim_sse2.hpp +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.hpp +blitter/common.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 +#end + +# Music +#if DEDICATED +#else +#if ALLEGRO + music/allegro_m.cpp +#end +#if DIRECTMUSIC + music/dmusic.cpp +#end +#end +music/null_m.cpp +music/midifile.cpp +#if DEDICATED +#else +#if WIN32 + music/win32_m.cpp +#else + #if DOS + #else + #if MORPHOS + #else + music/extmidi.cpp + #end + #end +#end +#if BEOS + music/bemidi.cpp +#end +#if LIBTIMIDITY + music/libtimidity.cpp +#end +#if FLUIDSYNTH + music/fluidsynth.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 + sound/xaudio2_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 + os/macosx/string_osx.cpp + #end +#end + +# Windows files +#if WIN32 + os/windows/crashlog_win.cpp + os/windows/ottdres.rc + os/windows/string_uniscribe.cpp + 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 0000000000..112b02a087 --- /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 0000000000..2111a8eb81 --- /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 0000000000..9748dc444f --- /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 0000000000..3cdda21f1b --- /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 0000000000..0a588a40a2 --- /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 0000000000..14fd89ef15 --- /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 0000000000..c1861aa033 --- /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 0000000000..40b5073ec6 --- /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 0000000000..34e4d7723e --- /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 0000000000..ded3c12e8a --- /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 0000000000..269a7e40d8 --- /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 0000000000..856c33f791 --- /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 0000000000..87e0ac0d69 --- /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 0000000000..540975fb5c --- /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 OCCURRED [%s]\n",sErr); + } + else{ + pf(v,"\nAN ERROR HAS OCCURRED [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 0000000000..0ff0090209 --- /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 0000000000..2bc3684a5e --- /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 0000000000..8639b6456a --- /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 0000000000..0d769bf1f7 --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqapi.cpp @@ -0,0 +1,1326 @@ +/* + * 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 0000000000..5c26352079 --- /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 0000000000..86a1b11858 --- /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 0000000000..aa1bca0443 --- /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 0000000000..895c053c24 --- /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 0000000000..a42dcd575a --- /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 0000000000..ace9d201e9 --- /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) : _token(0), _fs(NULL), _lex(_ss(v), rg, up, ThrowError, this), _debugline(0), _debugop(0) + { + _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 0000000000..b29917390b --- /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 0000000000..2f24e83b66 --- /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("comparison 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 = 0x00000001LL << 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 0000000000..e58ccd2994 --- /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 0000000000..5415b566e8 --- /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 0000000000..c0bf1e5e9e --- /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 0000000000..77c487a269 --- /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 0000000000..b53b309d6b --- /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 0000000000..5c1b3966aa --- /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 0000000000..d48baca1e9 --- /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 0000000000..d71e515a8d --- /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 0000000000..a9e4a8743c --- /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 0000000000..3cebdd11ac --- /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 0000000000..35878e197b --- /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 0000000000..da6bf9ae64 --- /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 0000000000..a5f298e1e2 --- /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 0000000000..60146fe738 --- /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 0000000000..52d9ba41ab --- /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 0000000000..3bf1a9dbad --- /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 0000000000..b1138dcb1a --- /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(static_cast(&_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 0000000000..03ffea2303 --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/sqvm.cpp @@ -0,0 +1,1607 @@ +/* + * 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)) + } + } + FALLTHROUGH; + 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 + } + } + FALLTHROUGH; + 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 = {}; + 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); + } + FALLTHROUGH; + 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; + } + FALLTHROUGH; + 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; + } + NOT_REACHED(); +} + +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 = {}; + 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; + } + } + FALLTHROUGH; + 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 0000000000..89a592e136 --- /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 0000000000..065367d03b --- /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 0000000000..ea26f32679 --- /dev/null +++ b/src/ai/ai_config.cpp @@ -0,0 +1,129 @@ +/* $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 +}; + +AIConfig::AIConfig(const AIConfig *config) : ScriptConfig(config) +{ + /* Override start_date as per AIConfig::AddRandomDeviation(). + * This is necessary because the ScriptConfig constructor will instead call + * ScriptConfig::AddRandomDeviation(). */ + int start_date = config->GetSetting("start_date"); + this->SetSetting("start_date", start_date != 0 ? max(1, this->GetSetting("start_date")) : 0); +} + +/* 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 0000000000..12cc02a497 --- /dev/null +++ b/src/ai/ai_config.hpp @@ -0,0 +1,52 @@ +/* $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); + + 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 0000000000..51522edaff --- /dev/null +++ b/src/ai/ai_core.cpp @@ -0,0 +1,394 @@ +/* $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 "../framerate_type.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) { + PerformanceMeasurer framerate((PerformanceElement)(PFE_AI0 + c->index)); + cur_company.Change(c->index); + c->ai_instance->GameLoop(); + } else { + PerformanceMeasurer::SetInactive((PerformanceElement)(PFE_AI0 + c->index)); + } + } + 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; + PerformanceMeasurer::SetInactive((PerformanceElement)(PFE_AI0 + company)); + + 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 0000000000..bc79d943bc --- /dev/null +++ b/src/ai/ai_gui.cpp @@ -0,0 +1,1571 @@ +/* $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 "../core/geometry_func.hpp" +#include "../guitimer_func.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. + GUITimer 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->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->RebuildVisibleSettings(); + } + + 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)); + } + } + + this->vscroll->SetCount((int)this->visible_settings.size()); + } + + 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 = this->IsEditableItem(config_item); + + 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 (!this->IsEditableItem(config_item)) 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.SetInterval(150); + } + } 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; + VisibleSettingsList::const_iterator it = this->visible_settings.begin(); + for (int i = 0; i < this->clicked_row; 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; + int32 value = atoi(str); + this->ai_config->SetSetting(config_item.name, value); + this->SetDirty(); + } + + virtual void OnDropdownSelect(int widget, int index) + { + assert(this->clicked_dropdown); + VisibleSettingsList::const_iterator it = this->visible_settings.begin(); + for (int i = 0; i < this->clicked_row; 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; + this->ai_config->SetSetting(config_item.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 OnRealtimeTick(uint delta_ms) + { + if (this->timeout.Elapsed(delta_ms)) { + 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(); + HideDropDownMenu(this); + DeleteChildWindows(WC_QUERY_STRING); + } + +private: + bool IsEditableItem(const ScriptConfigItem config_item) const + { + return _game_mode == GM_MENU || ((this->slot != OWNER_DEITY) && !Company::IsValidID(this->slot)) || (config_item.flags & SCRIPTCONFIG_INGAME) != 0; + } +}; + +/** 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) +{ + DeleteWindowById(WC_TEXTFILE, file_type); + 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; + + case WID_AIC_CHANGE: { + SetDParam(0, STR_AI_CONFIG_CHANGE_GAMESCRIPT); + Dimension dim = GetStringBoundingBox(STR_AI_CONFIG_CHANGE); + + SetDParam(0, STR_AI_CONFIG_CHANGE_NONE); + dim = maxdim(dim, GetStringBoundingBox(STR_AI_CONFIG_CHANGE)); + + SetDParam(0, STR_AI_CONFIG_CHANGE_AI); + dim = maxdim(dim, GetStringBoundingBox(STR_AI_CONFIG_CHANGE)); + + dim.width += padding.width; + dim.height += padding.height; + *size = maxdim(*size, dim); + 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); + 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, 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, CCA_DELETE | ai_debug_company << 16 | CRR_MANUAL << 24, 0, CMD_COMPANY_CTRL); + DoCommandP(0, CCA_NEW_AI | 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 0000000000..ad6eed8fd1 --- /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 0000000000..43a4345460 --- /dev/null +++ b/src/ai/ai_info.cpp @@ -0,0 +1,184 @@ +/* $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 || strcmp(api_version, "1.6") == 0 || strcmp(api_version, "1.7") == 0 || + strcmp(api_version, "1.8") == 0 || strcmp(api_version, "1.9") == 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 0000000000..51cfb7d8a0 --- /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 0000000000..76e8efd27c --- /dev/null +++ b/src/ai/ai_instance.cpp @@ -0,0 +1,272 @@ +/* $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. + * @param cmd cmd as given to DoCommandPInternal. + */ +void CcAI(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd) +{ + /* + * 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; + + if (c->ai_instance->DoCommandCallback(result, tile, p1, p2, cmd)) { + 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 0000000000..204bf9712a --- /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 0000000000..5f16de3f91 --- /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); + /* Continue, 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 0000000000..d8e8a6993d --- /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 0000000000..f4fce09be1 --- /dev/null +++ b/src/aircraft.h @@ -0,0 +1,150 @@ +/* $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. + + VAF_HELI_DIRECT_DESCENT = 3, ///< The helicopter is descending directly at its destination (helipad or in front of hangar) +}; + +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(); + ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_AIRCRAFT_INC : EXPENSES_AIRCRAFT_RUN; } + bool IsPrimaryVehicle() const { return this->IsNormalAircraft(); } + void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) 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 aircraft. + */ +#define FOR_ALL_AIRCRAFT(var) FOR_ALL_VEHICLES_OF_TYPE(Aircraft, var) + +void GetRotorImage(const Aircraft *v, EngineImageType image_type, VehicleSpriteSeq *result); + +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 0000000000..08c634ba20 --- /dev/null +++ b/src/aircraft_cmd.cpp @@ -0,0 +1,2122 @@ +/* $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 "zoom_func.h" +#include "disaster_vehicle.h" +#include "newgrf_airporttiles.h" +#include "framerate_type.h" + +#include "table/strings.h" + +#include "safeguards.h" + +void Aircraft::UpdateDeltaXY() +{ + 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 (st->owner != v->owner || !(st->facilities & FACIL_AIRPORT) || !st->airport.HasHangar()) continue; + + const AirportFTAClass *afc = st->airport.GetFTA(); + + /* don't crash the plane if we know it can't land at the airport */ + if ((afc->flags & AirportFTAClass::SHORT_STRIP) && (avi->subtype & AIR_FAST) && !_cheats.no_jetcrash.value) continue; + + /* the plane won't land at any helicopter station */ + if (!(afc->flags & AirportFTAClass::AIRPLANES) && (avi->subtype & AIR_CTOL)) 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; +} + +void Aircraft::GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const +{ + uint8 spritenum = this->spritenum; + + if (is_custom_sprite(spritenum)) { + GetCustomVehicleSprite(this, direction, image_type, result); + if (result->IsValid()) return; + + spritenum = this->GetEngine()->original_image_index; + } + + assert(IsValidImageIndex(spritenum)); + result->Set(direction + _aircraft_sprite[spritenum]); +} + +void GetRotorImage(const Aircraft *v, EngineImageType image_type, VehicleSpriteSeq *result) +{ + assert(v->subtype == AIR_HELICOPTER); + + const Aircraft *w = v->Next()->Next(); + if (is_custom_sprite(v->spritenum)) { + GetCustomRotorSprite(v, false, image_type, result); + if (result->IsValid()) return; + } + + /* Return standard rotor sprites if there are no custom sprites for this helicopter */ + result->Set(SPR_ROTOR_STOPPED + w->state); +} + +static void GetAircraftIcon(EngineID engine, EngineImageType image_type, VehicleSpriteSeq *result) +{ + const Engine *e = Engine::Get(engine); + uint8 spritenum = e->u.air.image_index; + + if (is_custom_sprite(spritenum)) { + GetCustomVehicleIcon(engine, DIR_W, image_type, result); + if (result->IsValid()) return; + + spritenum = e->original_image_index; + } + + assert(IsValidImageIndex(spritenum)); + result->Set(DIR_W + _aircraft_sprite[spritenum]); +} + +void DrawAircraftEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type) +{ + VehicleSpriteSeq seq; + GetAircraftIcon(engine, image_type, &seq); + + Rect rect; + seq.GetBounds(&rect); + preferred_x = Clamp(preferred_x, + left - UnScaleGUI(rect.left), + right - UnScaleGUI(rect.right)); + + seq.Draw(preferred_x, y, pal, pal == PALETTE_CRASH); + + if (!(AircraftVehInfo(engine)->subtype & AIR_CTOL)) { + VehicleSpriteSeq rotor_seq; + GetCustomRotorIcon(engine, image_type, &rotor_seq); + if (!rotor_seq.IsValid()) rotor_seq.Set(SPR_ROTOR_STOPPED); + rotor_seq.Draw(preferred_x, y - ScaleGUITrad(5), PAL_NONE, false); + } +} + +/** + * 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) +{ + VehicleSpriteSeq seq; + GetAircraftIcon(engine, image_type, &seq); + + Rect rect; + seq.GetBounds(&rect); + + width = UnScaleGUI(rect.right - rect.left + 1); + height = UnScaleGUI(rect.bottom - rect.top + 1); + xoffs = UnScaleGUI(rect.left); + yoffs = UnScaleGUI(rect.top); +} + +/** + * 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[out] ret 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(); + + u->subtype = AIR_SHADOW; + u->UpdateDeltaXY(); + + 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->sprite_seq.Set(SPR_IMG_QUERY); + u->sprite_seq.Set(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->sprite_seq.Set(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(); + + 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 || !CanVehicleUseStation(this, st) || !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; + + VehicleSpriteSeq seq; + if (spd == 0) { + u->state = HRS_ROTOR_STOPPED; + GetRotorImage(v, EIT_ON_MAP, &seq); + if (u->sprite_seq == seq) return; + } else if (tick >= spd) { + u->tick_counter = 0; + u->state++; + if (u->state > HRS_ROTOR_MOVING_3) u->state = HRS_ROTOR_MOVING_1; + GetRotorImage(v, EIT_ON_MAP, &seq); + } else { + return; + } + + u->sprite_seq = seq; + + 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) { + GetRotorImage(v, EIT_ON_MAP, &v->Next()->Next()->sprite_seq); + } + + 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->sprite_seq.CopyWithoutPalette(v->sprite_seq); // the shadow is never coloured + + 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; + + /* adjust speed for broken vehicles */ + if (v->vehstatus & VS_AIRCRAFT_BROKEN) { + if (SPEED_LIMIT_BROKEN < speed_limit) hard_limit = false; + speed_limit = min(speed_limit, SPEED_LIMIT_BROKEN); + } + + 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); + + /* 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, aircraft 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); +template int GetAircraftFlightLevel(Aircraft *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) { + SetBit(v->flags, VAF_HELI_DIRECT_DESCENT); + + 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) { + ClrBit(v->flags, VAF_HELI_DIRECT_DESCENT); + 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) { + GetRotorImage(this, EIT_ON_MAP, &this->Next()->Next()->sprite_seq); + } +} + + +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) +{ + Station *st = Station::Get(v->targetairport); + + TileIndex vt = TileVirtXY(v->x_pos, v->y_pos); + + v->UpdateDeltaXY(); + + AirportTileAnimationTrigger(st, vt, AAT_STATION_AIRPLANE_LAND); + + 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 && Station::Get(v->targetairport)->airport.HasHangar()) { + 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(); +} + +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(); + + /* 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) && (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 + if (v->state == HELILANDING) SetBit(v->flags, VAF_HELI_DIRECT_DESCENT); + /* 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(); +} + +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 apc 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; + + PerformanceAccumulator framerate(PFE_GL_AIRCRAFT); + + 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); + + Order *o = &v->current_order; + /* The aircraft is heading to a hangar, but the new station doesn't have one, + * or the aircraft can't land on the new station. Cancel current order. */ + if (o->IsType(OT_GOTO_DEPOT) && !(o->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) && o->GetDestination() == st->index && + (!st->airport.HasHangar() || !CanVehicleUseStation(v, st))) { + o->MakeDummy(); + SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); + } + v->pos = v->previous_pos = AircraftGetEntryPoint(v, ap, rotation); + UpdateAircraftCache(v); + } + + /* Heliports don't have a hangar. Invalidate all go to hangar orders from all aircraft. */ + if (!st->airport.HasHangar()) RemoveOrderFromAllVehicles(OT_GOTO_DEPOT, st->index, true); +} diff --git a/src/aircraft_gui.cpp b/src/aircraft_gui.cpp new file mode 100644 index 0000000000..6693b1f8ad --- /dev/null +++ b/src/aircraft_gui.cpp @@ -0,0 +1,115 @@ +/* $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; + + VehicleSpriteSeq seq; + v->GetImage(rtl ? DIR_E : DIR_W, image_type, &seq); + + Rect rect; + seq.GetBounds(&rect); + + int width = UnScaleGUI(rect.right - rect.left + 1); + int x_offs = UnScaleGUI(rect.left); + 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); + seq.Draw(x, y + y_offs, pal, (v->vehstatus & VS_CRASHED) != 0); + if (helicopter) { + const Aircraft *a = Aircraft::From(v); + VehicleSpriteSeq rotor_seq; + GetCustomRotorSprite(a, true, image_type, &rotor_seq); + if (!rotor_seq.IsValid()) rotor_seq.Set(SPR_ROTOR_STOPPED); + heli_offs = ScaleGUITrad(5); + rotor_seq.Draw(x, y + y_offs - heli_offs, PAL_NONE, false); + } + if (v->index == selection) { + x += x_offs; + y += UnScaleGUI(rect.top) + y_offs - heli_offs; + DrawFrameRect(x - 1, y - 1, x + width + 1, y + UnScaleGUI(rect.bottom - rect.top + 1) + heli_offs + 1, COLOUR_WHITE, FR_BORDERONLY); + } +} diff --git a/src/airport.cpp b/src/airport.cpp new file mode 100644 index 0000000000..7985e017aa --- /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 const 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 0000000000..31c68ef002 --- /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 0000000000..71b3b50133 --- /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, uint32 cmd) +{ + 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 OnRealtimeTick(uint delta_ms) + { + 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 0000000000..2a4cd89583 --- /dev/null +++ b/src/animated_tile.cpp @@ -0,0 +1,79 @@ +/* $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 "core/smallvec_type.hpp" +#include "tile_cmd.h" +#include "viewport_func.h" +#include "framerate_type.h" + +#include "safeguards.h" + +/** The table/list with animated tiles. */ +SmallVector _animated_tiles; + +/** + * Removes the given tile from the animated tile table. + * @param tile the tile to remove + */ +void DeleteAnimatedTile(TileIndex tile) +{ + TileIndex *to_remove = _animated_tiles.Find(tile); + if (to_remove != _animated_tiles.End()) { + /* The order of the remaining elements must stay the same, otherwise the animation loop may miss a tile. */ + _animated_tiles.ErasePreservingOrder(to_remove); + MarkTileDirtyByTile(tile); + } +} + +/** + * 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); + _animated_tiles.Include(tile); +} + +/** + * Animate all tiles in the animated tile list, i.e.\ call AnimateTile on them. + */ +void AnimateAnimatedTiles() +{ + PerformanceAccumulator framerate(PFE_GL_LANDSCAPE); + + const TileIndex *ti = _animated_tiles.Begin(); + while (ti < _animated_tiles.End()) { + 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_tiles.Clear(); +} diff --git a/src/animated_tile_func.h b/src/animated_tile_func.h new file mode 100644 index 0000000000..9634ecdee3 --- /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 0000000000..44ad587895 --- /dev/null +++ b/src/articulated_vehicles.cpp @@ -0,0 +1,451 @@ +/* $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 CargoTypes GetAvailableVehicleCargoTypes(EngineID engine, bool include_initial_cargo_type) +{ + const Engine *e = Engine::Get(engine); + if (!e->CanCarryCargo()) return 0; + + CargoTypes 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, CargoTypes *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, CargoTypes *union_mask, CargoTypes *intersection_mask) +{ + const Engine *e = Engine::Get(engine); + CargoTypes veh_cargoes = GetAvailableVehicleCargoTypes(engine, include_initial_cargo_type); + *union_mask = veh_cargoes; + *intersection_mask = (veh_cargoes != 0) ? veh_cargoes : ALL_CARGOTYPES; + + 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 + */ +CargoTypes GetUnionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type) +{ + CargoTypes 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) + */ +CargoTypes GetIntersectionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type) +{ + CargoTypes 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(); + + CargoTypes 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); + + CargoTypes real_refit_union = 0; + CargoTypes real_refit_intersection = ALL_CARGOTYPES; + CargoArray real_default_capacity; + + do { + CargoTypes 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->date_of_last_service = first->date_of_last_service; + 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->sprite_seq.Set(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 0000000000..77322fb4c7 --- /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, CargoTypes *union_mask, CargoTypes *intersection_mask); +CargoTypes GetUnionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type); +CargoTypes 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 0000000000..3b7f739726 --- /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 0000000000..5d265866d8 --- /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 0000000000..95568e3811 --- /dev/null +++ b/src/autoreplace_cmd.cpp @@ -0,0 +1,789 @@ +/* $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 "vehiclelist.h" + +#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 + * @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) +{ + CargoTypes available_cargoes_a = GetUnionOfArticulatedRefitMasks(engine_a, true); + CargoTypes 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) +{ + CargoTypes union_refit_mask_a = GetUnionOfArticulatedRefitMasks(v->engine_type, false); + CargoTypes 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) +{ + CargoTypes 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); + + const VehicleType vt = Engine::Get(old_engine_type)->type; + SetWindowDirty(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_GROUP_LIST, vt, _current_company).Pack()); + } + 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 0000000000..3a6fc83a81 --- /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 0000000000..eae0a378eb --- /dev/null +++ b/src/autoreplace_gui.cpp @@ -0,0 +1,709 @@ +/* $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 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. #INVALID_RAILTYPE to show all. + 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 && this->sel_railtype != INVALID_RAILTYPE) { + /* 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) + { + this->sel_railtype = INVALID_RAILTYPE; + 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_DROPDOWN: { + Dimension d = GetStringBoundingBox(STR_REPLACE_ENGINES); + d = maxdim(d, GetStringBoundingBox(STR_REPLACE_WAGONS)); + 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_DROPDOWN: + 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) { + /* Show the selected railtype in the pulldown menu */ + this->GetWidget(WID_RV_TRAIN_RAILTYPE_DROPDOWN)->widget_data = sel_railtype == INVALID_RAILTYPE ? STR_REPLACE_ALL_RAILTYPE : 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_DROPDOWN: { + DropDownList *list = new DropDownList(); + *list->Append() = new DropDownListStringItem(STR_REPLACE_ENGINES, 1, false); + *list->Append() = new DropDownListStringItem(STR_REPLACE_WAGONS, 0, false); + ShowDropDownList(this, list, this->replace_engines ? 1 : 0, WID_RV_TRAIN_ENGINEWAGON_DROPDOWN); + break; + } + + case WID_RV_TRAIN_RAILTYPE_DROPDOWN: // Railtype selection dropdown menu + ShowDropDownList(this, GetRailTypeDropDownList(true, 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_TRAIN_ENGINEWAGON_DROPDOWN: { + this->replace_engines = index != 0; + this->engines[0].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(NWID_VERTICAL), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_RV_TRAIN_RAILTYPE_DROPDOWN), SetMinimalSize(136, 12), SetDataTip(0x0, STR_REPLACE_HELP_RAILTYPE), SetFill(1, 0), SetResize(1, 0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_RV_TRAIN_ENGINEWAGON_DROPDOWN), SetDataTip(STR_BLACK_STRING, STR_REPLACE_ENGINE_WAGON_SELECT_HELP), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 0), EndContainer(), + 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(NWID_VERTICAL), + NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_RIGHT_DETAILS), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_TRAIN_WAGONREMOVE_TOGGLE), SetMinimalSize(138, 12), SetDataTip(STR_REPLACE_REMOVE_WAGON, STR_REPLACE_REMOVE_WAGON_HELP), SetFill(1, 0), 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), + 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 0000000000..046ac89921 --- /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 0000000000..30ba7e2b44 --- /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 0000000000..e504610c39 --- /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 0000000000..200512786c --- /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 0000000000..3679afd351 --- /dev/null +++ b/src/base_consist.h @@ -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 base_consist.h Properties for front vehicles/consists. */ + +#ifndef BASE_CONSIST_H +#define BASE_CONSIST_H + +#include "order_type.h" +#include "date_type.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 0000000000..b040abcf9d --- /dev/null +++ b/src/base_media_base.h @@ -0,0 +1,326 @@ +/* $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_UNKNOWN, ///< The file has not been checked yet + 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 check_result; ///< cached result of md5 check + + 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); +}; + +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; + +/** + * 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; + +/* Functions to read DOS music CAT files, similar to but not quite the same as sound effect CAT files */ +char *GetMusicCatEntryName(const char *filename, size_t entrynum); +byte *GetMusicCatEntryData(const char *filename, size_t entrynum, size_t &entrylen); + +enum MusicTrackType { + MTT_STANDARDMIDI, ///< Standard MIDI file + MTT_MPSMIDI, ///< MPS GM driver MIDI format (contained in a CAT file) +}; + +/** Metadata about a music track. */ +struct MusicSongInfo { + char songname[32]; ///< name of song displayed in UI + byte tracknr; ///< track number of song displayed in UI + const char *filename; ///< file on disk containing song (when used in MusicSet class, this pointer is owned by MD5File object for the file) + MusicTrackType filetype; ///< decoder required for song file + int cat_index; ///< entry index in CAT file, for filetype==MTT_MPSMIDI + bool loop; ///< song should play in a tight loop if possible, never ending + int override_start; ///< MIDI ticks to skip over in beginning + int override_end; ///< MIDI tick to end the song at (0 if no override) +}; + +/** All data of a music set. */ +struct MusicSet : BaseSet { + /** Data about individual songs in set. */ + MusicSongInfo songinfo[NUM_SONGS_AVAILABLE]; + /** Number of valid songs in set. */ + 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 0000000000..f7afca0edb --- /dev/null +++ b/src/base_media_func.h @@ -0,0 +1,411 @@ +/* $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" + +/** + * 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) +{ + 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); + } + + file->check_result = T::CheckMD5(file, BASESET_DIR); + switch (file->check_result) { + case MD5File::CR_UNKNOWN: + break; + + 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 0000000000..cd512c5177 --- /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. + CargoTypes 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 0000000000..27b1fbd5b8 --- /dev/null +++ b/src/blitter/32bpp_anim.cpp @@ -0,0 +1,543 @@ +/* $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 "common.hpp" + +#include "../table/sprites.h" + +#include "../safeguards.h" + +/** Instantiation of the 32bpp with animation blitter factory. */ +static FBlitter_32bppAnim iFBlitter_32bppAnim; + +Blitter_32bppAnim::~Blitter_32bppAnim() +{ + free(this->anim_alloc); +} + +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 + this->ScreenToAnimOffset((uint32 *)bp->dst) + bp->top * this->anim_buf_pitch + 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_pitch; + + 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 = this->anim_buf + this->ScreenToAnimOffset((uint32 *)dst); + + 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_pitch; + } 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_pitch; + } 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[this->ScreenToAnimOffset((uint32 *)video) + x + y * this->anim_buf_pitch] = colour | (DEFAULT_BRIGHTNESS << 8); +} + +void Blitter_32bppAnim::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash) +{ + const Colour c = LookupColourInPalette(colour); + + if (_screen_disable_anim) { + this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [&](int x, int y) { + *((Colour *)video + x + y * _screen.pitch) = c; + }); + } else { + uint16 * const offset_anim_buf = this->anim_buf + this->ScreenToAnimOffset((uint32 *)video); + const uint16 anim_colour = colour | (DEFAULT_BRIGHTNESS << 8); + this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [&](int x, int y) { + *((Colour *)video + x + y * _screen.pitch) = c; + offset_anim_buf[x + y * this->anim_buf_pitch] = anim_colour; + }); + } +} + +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 = this->ScreenToAnimOffset((uint32 *)video) + 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_pitch; + } 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 = this->ScreenToAnimOffset((uint32 *)video) + 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(static_cast(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_pitch; + + /* 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; + + if (this->anim_buf == NULL) return; + + const uint16 *anim_line = this->ScreenToAnimOffset((const uint32 *)video) + 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_pitch; + } +} + +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_pitch; + src = dst - scroll_y * this->anim_buf_pitch; + + /* 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_pitch; + dst -= this->anim_buf_pitch; + } + } else { + /* Calculate pointers */ + dst = this->anim_buf + left + top * this->anim_buf_pitch; + src = dst - scroll_y * this->anim_buf_pitch; + + /* 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_pitch; + dst += this->anim_buf_pitch; + } + } + + 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 */ + const int width = this->anim_buf_width; + const int pitch_offset = _screen.pitch - width; + const int anim_pitch_offset = this->anim_buf_pitch - width; + for (int y = this->anim_buf_height; y != 0 ; y--) { + for (int x = width; x != 0 ; x--) { + uint16 value = *anim; + uint8 colour = GB(value, 0, 8); + if (colour >= PALETTE_ANIM_START) { + /* Update this pixel */ + *dst = this->AdjustBrightness(LookupColourInPalette(colour), GB(value, 8, 8)); + } + dst++; + anim++; + } + dst += pitch_offset; + anim += anim_pitch_offset; + } + + /* 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 || + _screen.pitch != this->anim_buf_pitch) { + /* The size of the screen changed; we can assume we can wipe all data from our buffer */ + free(this->anim_alloc); + this->anim_buf_width = _screen.width; + this->anim_buf_height = _screen.height; + this->anim_buf_pitch = (_screen.width + 7) & ~7; + this->anim_alloc = CallocT(this->anim_buf_pitch * this->anim_buf_height + 8); + + /* align buffer to next 16 byte boundary */ + this->anim_buf = reinterpret_cast((reinterpret_cast(this->anim_alloc) + 0xF) & (~0xF)); + } +} diff --git a/src/blitter/32bpp_anim.hpp b/src/blitter/32bpp_anim.hpp new file mode 100644 index 0000000000..ecf6dcfca0 --- /dev/null +++ b/src/blitter/32bpp_anim.hpp @@ -0,0 +1,83 @@ +/* $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 + void *anim_alloc; ///< The raw allocated buffer, not necessarily aligned correctly + int anim_buf_width; ///< The width of the animation buffer. + int anim_buf_height; ///< The height of the animation buffer. + int anim_buf_pitch; ///< The pitch of the animation buffer (width rounded up to 16 byte boundary). + Palette palette; ///< The current palette. + +public: + Blitter_32bppAnim() : + anim_buf(NULL), + anim_alloc(NULL), + anim_buf_width(0), + anim_buf_height(0), + anim_buf_pitch(0) + { + this->palette = _cur_palette; + } + + ~Blitter_32bppAnim(); + + /* 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 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 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]; + } + + inline int ScreenToAnimOffset(const uint32 *video) + { + int raw_offset = video - (const uint32 *)_screen.dst_ptr; + if (_screen.pitch == this->anim_buf_pitch) return raw_offset; + int lines = raw_offset / _screen.pitch; + int across = raw_offset % _screen.pitch; + return across + (lines * this->anim_buf_pitch); + } + + 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_sse2.cpp b/src/blitter/32bpp_anim_sse2.cpp new file mode 100644 index 0000000000..d5fa4268a8 --- /dev/null +++ b/src/blitter/32bpp_anim_sse2.cpp @@ -0,0 +1,100 @@ +/* $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 a partially SSSE2 32bpp blitter with animation support. */ + +#ifdef WITH_SSE + +#include "../stdafx.h" +#include "../video/video_driver.hpp" +#include "32bpp_anim_sse2.hpp" +#include "32bpp_sse_func.hpp" + +#include "../safeguards.h" + +/** Instantiation of the partially SSSE2 32bpp with animation blitter factory. */ +static FBlitter_32bppSSE2_Anim iFBlitter_32bppSSE2_Anim; + +void Blitter_32bppSSE2_Anim::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; + + bool screen_dirty = false; + + /* Let's walk the anim buffer and try to find the pixels */ + const int width = this->anim_buf_width; + const int screen_pitch = _screen.pitch; + const int anim_pitch = this->anim_buf_pitch; + __m128i anim_cmp = _mm_set1_epi16(PALETTE_ANIM_START - 1); + __m128i brightness_cmp = _mm_set1_epi16(Blitter_32bppBase::DEFAULT_BRIGHTNESS); + __m128i colour_mask = _mm_set1_epi16(0xFF); + for (int y = this->anim_buf_height; y != 0 ; y--) { + Colour *next_dst_ln = dst + screen_pitch; + const uint16 *next_anim_ln = anim + anim_pitch; + int x = width; + while (x > 0) { + __m128i data = _mm_load_si128((const __m128i *) anim); + + /* low bytes only, shifted into high positions */ + __m128i colour_data = _mm_and_si128(data, colour_mask); + + /* test if any colour >= PALETTE_ANIM_START */ + int colour_cmp_result = _mm_movemask_epi8(_mm_cmpgt_epi16(colour_data, anim_cmp)); + if (colour_cmp_result) { + /* test if any brightness is unexpected */ + if (x < 8 || colour_cmp_result != 0xFFFF || + _mm_movemask_epi8(_mm_cmpeq_epi16(_mm_srli_epi16(data, 8), brightness_cmp)) != 0xFFFF) { + /* slow path: < 8 pixels left or unexpected brightnesses */ + for (int z = min(x, 8); z != 0 ; z--) { + int value = _mm_extract_epi16(data, 0); + uint8 colour = GB(value, 0, 8); + if (colour >= PALETTE_ANIM_START) { + /* Update this pixel */ + *dst = AdjustBrightneSSE(LookupColourInPalette(colour), GB(value, 8, 8)); + screen_dirty = true; + } + data = _mm_srli_si128(data, 2); + dst++; + } + } else { + /* medium path: 8 pixels to animate all of expected brightnesses */ + for (int z = 0; z < 8; z++) { + *dst = LookupColourInPalette(_mm_extract_epi16(colour_data, 0)); + colour_data = _mm_srli_si128(colour_data, 2); + dst++; + } + screen_dirty = true; + } + } else { + /* fast path, no animation */ + dst += 8; + } + anim += 8; + x -= 8; + } + dst = next_dst_ln; + anim = next_anim_ln; + } + + if (screen_dirty) { + /* Make sure the backend redraws the whole screen */ + VideoDriver::GetInstance()->MakeDirty(0, 0, _screen.width, _screen.height); + } +} + +#endif /* WITH_SSE */ diff --git a/src/blitter/32bpp_anim_sse2.hpp b/src/blitter/32bpp_anim_sse2.hpp new file mode 100644 index 0000000000..0d4a5f1e65 --- /dev/null +++ b/src/blitter/32bpp_anim_sse2.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_anim.hpp A partially SSE2 32 bpp blitter with animation support. */ + +#ifndef BLITTER_32BPP_SSE2_ANIM_HPP +#define BLITTER_32BPP_SSE2_ANIM_HPP + +#ifdef WITH_SSE + +#ifndef SSE_VERSION +#define SSE_VERSION 2 +#endif + +#ifndef FULL_ANIMATION +#define FULL_ANIMATION 1 +#endif + +#include "32bpp_anim.hpp" +#include "32bpp_sse2.hpp" + +/** A partially 32 bpp blitter with palette animation. */ +class Blitter_32bppSSE2_Anim : public Blitter_32bppAnim { +public: + /* virtual */ void PaletteAnimate(const Palette &palette); + /* virtual */ const char *GetName() { return "32bpp-sse2-anim"; } +}; + +/** Factory for the partially 32bpp blitter with animation. */ +class FBlitter_32bppSSE2_Anim : public BlitterFactory { +public: + FBlitter_32bppSSE2_Anim() : BlitterFactory("32bpp-sse2-anim", "32bpp partially SSE2 Animation Blitter (palette animation)", HasCPUIDFlag(1, 3, 26)) {} + /* virtual */ Blitter *CreateInstance() { return new Blitter_32bppSSE2_Anim(); } +}; + +#endif /* WITH_SSE */ +#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 0000000000..24d1d7531f --- /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_anim_sse4.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 + this->ScreenToAnimOffset((uint32 *)bp->dst) + bp->top * this->anim_buf_pitch + 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_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 + */ +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 0000000000..ee678bc164 --- /dev/null +++ b/src/blitter/32bpp_anim_sse4.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 32bpp_anim_sse4.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_anim_sse2.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_32bppSSE2_Anim, 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", "32bpp 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 0000000000..b2e66b0be1 --- /dev/null +++ b/src/blitter/32bpp_base.cpp @@ -0,0 +1,188 @@ +/* $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 "common.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::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash) +{ + const Colour c = LookupColourInPalette(colour); + this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [=](int x, int y) { + *((Colour *)video + x + y * _screen.pitch) = c; + }); +} + +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 */ +} + +Colour Blitter_32bppBase::ReallyAdjustBrightness(Colour colour, uint8 brightness) +{ + assert(DEFAULT_BRIGHTNESS == 1 << 7); + + uint64 combined = (((uint64) colour.r) << 32) | (((uint64) colour.g) << 16) | ((uint64) colour.b); + combined *= brightness; + + uint16 r = GB(combined, 39, 9); + uint16 g = GB(combined, 23, 9); + uint16 b = GB(combined, 7, 9); + + if ((combined & 0x800080008000L) == 0L) { + return Colour(r, g, b, colour.a); + } + + uint16 ob = 0; + /* Sum overbright */ + if (r > 255) ob += r - 255; + if (g > 255) ob += g - 255; + if (b > 255) ob += b - 255; + + /* 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); +} + +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 0000000000..697593da6a --- /dev/null +++ b/src/blitter/32bpp_base.hpp @@ -0,0 +1,161 @@ +/* $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 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 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 Colour ReallyAdjustBrightness(Colour colour, uint8 brightness); + + static inline Colour AdjustBrightness(Colour colour, uint8 brightness) + { + /* Shortcut for normal brightness */ + if (brightness == DEFAULT_BRIGHTNESS) return colour; + + return ReallyAdjustBrightness(colour, brightness); + } +}; + +#endif /* BLITTER_32BPP_BASE_HPP */ diff --git a/src/blitter/32bpp_optimized.cpp b/src/blitter/32bpp_optimized.cpp new file mode 100644 index 0000000000..cc056f5b59 --- /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 0000000000..c261aa33d6 --- /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 0000000000..92375be165 --- /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 0000000000..0751f6f753 --- /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 0000000000..ae2b3ccc52 --- /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 0000000000..d6b17f679c --- /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 0000000000..723264f03f --- /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 0000000000..9c59d253f5 --- /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 0000000000..fb0ce9eb6e --- /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 0000000000..49c7a68c20 --- /dev/null +++ b/src/blitter/32bpp_sse_type.h @@ -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 . + */ + +/** @file 32bpp_sse_type.h Types related to SSE 32 bpp blitter. */ + +#ifndef BLITTER_32BPP_SSE_TYPE_H +#define BLITTER_32BPP_SSE_TYPE_H + +#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. + +#undef ALIGN + +#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_H */ diff --git a/src/blitter/32bpp_ssse3.cpp b/src/blitter/32bpp_ssse3.cpp new file mode 100644 index 0000000000..ab6c9eba5d --- /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 0000000000..e9cac8ff0b --- /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 0000000000..dccfda3d70 --- /dev/null +++ b/src/blitter/8bpp_base.cpp @@ -0,0 +1,162 @@ +/* $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 "common.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::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash) +{ + this->DrawLineGeneric(x, y, x2, y2, screen_width, screen_height, width, dash, [=](int x, int y) { + *((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 0000000000..8f75dda5d3 --- /dev/null +++ b/src/blitter/8bpp_base.hpp @@ -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 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 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 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 0000000000..0f07e7c7bb --- /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 0000000000..b5b5324b91 --- /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 0000000000..2131a04682 --- /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: + if (*src != 0) *dst = 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 0000000000..c00c75ac04 --- /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.hpp b/src/blitter/base.hpp new file mode 100644 index 0000000000..388359441f --- /dev/null +++ b/src/blitter/base.hpp @@ -0,0 +1,210 @@ +/* $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) = 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() { } + + template void DrawLineGeneric(int x, int y, int x2, int y2, int screen_width, int screen_height, int width, int dash, SetPixelT set_pixel); +}; + +#endif /* BLITTER_BASE_HPP */ diff --git a/src/blitter/common.hpp b/src/blitter/common.hpp new file mode 100644 index 0000000000..3e4911d003 --- /dev/null +++ b/src/blitter/common.hpp @@ -0,0 +1,197 @@ +/* $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 common.hpp Common functionality for all blitter implementations. */ + +#ifndef BLITTER_COMMON_HPP +#define BLITTER_COMMON_HPP + +#include "base.hpp" +#include "../core/math_func.hpp" + +#include + +template +void Blitter::DrawLineGeneric(int x, int y, int x2, int y2, int screen_width, int screen_height, int width, int dash, SetPixelT set_pixel) +{ + 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) set_pixel(x, y); + 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) */ + int64 frac_sq = ((int64) width) * ((int64) width) * (((int64) dx) * ((int64) dx) + ((int64) dy) * ((int64) dy)); + int frac_max = 3 * frac_diff / 2; + while (frac_diff < frac_max) { + int frac_test = (frac_diff + frac_max) / 2; + if (((int64) frac_test) * ((int64) 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) { + if (stepx < 0) { + std::swap(x, x2); + std::swap(y, y2); + stepy = -stepy; + } + if (x2 < 0 || x >= screen_width) return; + + 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)) { + frac_low += dx; + y_low -= stepy; + } + while (frac_high >= dx / 2) { + frac_high -= dx; + y_high += stepy; + } + + if (x < 0) { + dash_count = (-x) % (dash + gap); + auto adjust_frac = [&](int64 frac, int &y_bound) -> int { + frac -= ((int64) dy) * ((int64) x); + if (frac >= 0) { + int quotient = frac / dx; + int remainder = frac % dx; + y_bound += (1 + quotient) * stepy; + frac = remainder - dx; + } + return frac; + }; + frac_low = adjust_frac(frac_low, y_low); + frac_high = adjust_frac(frac_high, y_high); + x = 0; + } + x2++; + if (x2 > screen_width) { + x2 = screen_width; + } + + while (x != x2) { + if (dash_count < dash) { + for (int y = y_low; y != y_high; y += stepy) { + if (y >= 0 && y < screen_height) set_pixel(x, y); + } + } + if (frac_low >= 0) { + y_low += stepy; + frac_low -= dx; + } + if (frac_high >= 0) { + y_high += stepy; + frac_high -= dx; + } + x++; + frac_low += dy; + frac_high += dy; + if (++dash_count >= dash + gap) dash_count = 0; + } + } else { + if (stepy < 0) { + std::swap(x, x2); + std::swap(y, y2); + stepx = -stepx; + } + if (y2 < 0 || y >= screen_height) return; + + 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)) { + frac_low += dy; + x_low -= stepx; + } + while (frac_high >= dy / 2) { + frac_high -= dy; + x_high += stepx; + } + + if (y < 0) { + dash_count = (-y) % (dash + gap); + auto adjust_frac = [&](int64 frac, int &x_bound) -> int { + frac -= ((int64) dx) * ((int64) y); + if (frac >= 0) { + int quotient = frac / dy; + int remainder = frac % dy; + x_bound += (1 + quotient) * stepx; + frac = remainder - dy; + } + return frac; + }; + frac_low = adjust_frac(frac_low, x_low); + frac_high = adjust_frac(frac_high, x_high); + y = 0; + } + y2++; + if (y2 > screen_height) { + y2 = screen_height; + } + + while (y != y2) { + if (dash_count < dash) { + for (int x = x_low; x != x_high; x += stepx) { + if (x >= 0 && x < screen_width) set_pixel(x, y); + } + } + if (frac_low >= 0) { + x_low += stepx; + frac_low -= dy; + } + if (frac_high >= 0) { + x_high += stepx; + frac_high -= dy; + } + y++; + frac_low += dx; + frac_high += dx; + if (++dash_count >= dash + gap) dash_count = 0; + } + } +} + +#endif /* BLITTER_COMMON_HPP */ diff --git a/src/blitter/factory.hpp b/src/blitter/factory.hpp new file mode 100644 index 0000000000..01faca68fd --- /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 0000000000..e968abe13f --- /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 0000000000..a6fed2ebca --- /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 0000000000..1033d89f11 --- /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 0000000000..cf2b538f39 --- /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 0000000000..3fb52a1f9e --- /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.md."); + return false; +} diff --git a/src/bridge.h b/src/bridge.h new file mode 100644 index 0000000000..badf045e39 --- /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 0000000000..fd6d46752c --- /dev/null +++ b/src/bridge_gui.cpp @@ -0,0 +1,436 @@ +/* $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-13) - rail type or road types. + * - p2 = (bit 15-16) - transport type. + * @param cmd unused + */ +void CcBuildBridge(const CommandCost &result, TileIndex end_tile, uint32 p1, uint32 p2, uint32 cmd) +{ + 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 0000000000..b738895065 --- /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 tile 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 t 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 0000000000..75b20498d1 --- /dev/null +++ b/src/bridge_map.h @@ -0,0 +1,184 @@ +/* $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 = 0; + _m[t].m4 = 0; + _m[t].m5 = 1 << 7 | tt << 2 | d; + SB(_me[t].m6, 2, 4, bridgetype); + _me[t].m7 = 0; + _me[t].m8 = rt; +} + +/** + * 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 0000000000..0ac23cfde6 --- /dev/null +++ b/src/build_vehicle_gui.cpp @@ -0,0 +1,1520 @@ +/* $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; + CargoTypes 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; + CargoTypes 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 in the buy window. + * @param left Left edge of the window to draw in. + * @param right Right edge of the window to draw in. + * @param y Top of the area to draw in. + * @param engine_number Engine to display. + * @param refittable If set, the aircraft can be refitted. + * @return Bottom of the used area. + */ +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; + + /* Aircraft type */ + SetDParam(0, e->GetAircraftTypeText()); + DrawString(left, right, y, STR_PURCHASE_INFO_AIRCRAFT_TYPE); + y += FONT_HEIGHT_NORMAL; + + /* Aircraft range, if available. */ + 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_PURCHASE_INFO_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->SetWidgetsDisabledState(this->sel_engine == INVALID_ENGINE, WID_BV_SHOW_HIDE, WID_BV_BUILD, WID_BV_RENAME, WIDGET_LIST_END); + + 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 0000000000..79d1c84f46 --- /dev/null +++ b/src/cargo_type.h @@ -0,0 +1,158 @@ +/* $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 CargoType { + /* 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 = 64, ///< 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. +}; + +/** Test whether cargo type is not CT_INVALID */ +inline bool IsCargoTypeValid(CargoType t) { return t != CT_INVALID; } +/** Test whether cargo type is not CT_INVALID */ +inline bool IsCargoIDValid(CargoID t) { return t != CT_INVALID; } + +typedef uint64 CargoTypes; + +static const CargoTypes ALL_CARGOTYPES = (CargoTypes)UINT64_MAX; + +/** 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 0000000000..96ddc3708e --- /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 0000000000..0311efcae1 --- /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 0000000000..40a029ac53 --- /dev/null +++ b/src/cargomonitor.cpp @@ -0,0 +1,161 @@ +/* $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. + * @param dest industry index where the cargo is delivered to. + */ +void AddCargoDelivery(CargoID cargo_type, CompanyID company, uint32 amount, SourceType src_type, SourceID src, const Station *st, IndustryID dest) +{ + 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++) { + if ((*ip)->index != dest) continue; + 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 0000000000..c7e5da135b --- /dev/null +++ b/src/cargomonitor.h @@ -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 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 = 6, ///< Number of bits of the cargo type field. + CCB_COMPANY_START = 25, ///< Start bit of the company field. + CCB_COMPANY_LENGTH = 4, ///< Number of bits of the company field. +}; + +assert_compile(NUM_CARGO <= (1 << CCB_CARGO_TYPE_LENGTH)); +assert_compile(MAX_COMPANIES <= (1 << CCB_COMPANY_LENGTH)); + + +/** + * 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)); + assert(company < (1 << CCB_COMPANY_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)); + assert(company < (1 << CCB_COMPANY_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, IndustryID dest = INVALID_INDUSTRY); + +#endif /* CARGOMONITOR_H */ diff --git a/src/cargopacket.cpp b/src/cargopacket.cpp new file mode 100644 index 0000000000..9e699d6f42 --- /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 next ID of the next station the cargo wants to go to. + * @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. + * @param 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. + * @param 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 0000000000..0ed4fd9bbc --- /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 0000000000..6cc02f63a3 --- /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. + */ +CargoTypes _cargo_mask; + +/** + * Bitmask of real cargo types available. Phony cargoes like regearing cargoes are excluded. + */ +CargoTypes _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 0000000000..71cd932bbf --- /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 CargoTypes _cargo_mask; +extern CargoTypes _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, CargoTypes, 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 0000000000..8b300c9668 --- /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 0000000000..e774abc686 --- /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 0000000000..1bbf68a868 --- /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 >= 10 + this->box_width + 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 0000000000..a75acf35e3 --- /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 0000000000..c4aeb3a52e --- /dev/null +++ b/src/clear_cmd.cpp @@ -0,0 +1,403 @@ +/* $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(TileHash(ti->x, ti->y), 0, 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 non-desert + * @param tile tile to check + * @return does this tile have at least one non-desert tile around? + */ +static inline bool NeighbourIsNormal(TileIndex tile) +{ + for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) { + TileIndex t = tile + TileOffsByDiagDir(dir); + if (!IsValidTile(t)) continue; + if (GetTropicZone(t) != TROPICZONE_DESERT) return true; + if (HasTileWaterClass(t) && GetWaterClass(t) == WATER_CLASS_SEA) return true; + } + return false; +} + +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 = NeighbourIsNormal(tile) ? 1 : 3; + } + + 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 0000000000..b128288d1b --- /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 0000000000..d24916de35 --- /dev/null +++ b/src/clear_map.h @@ -0,0 +1,325 @@ +/* $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; + _me[t].m8 = 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; + _me[t].m8 = 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 0000000000..569708dfc5 --- /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 0000000000..6828633723 --- /dev/null +++ b/src/command.cpp @@ -0,0 +1,808 @@ +/* $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 "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 CmdScrollViewport; + +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 CmdSetGroupLivery; + +CommandProc CmdMoveOrder; +CommandProc CmdChangeTimetable; +CommandProc CmdSetVehicleOnTime; +CommandProc CmdAutofillTimetable; +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(CmdScrollViewport, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_SCROLL_VIEWPORT + + 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(CmdSetGroupLivery, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_GROUP_LIVERY + 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(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, cmd); + } + + return res.Succeeded(); +} + + +/** + * Helper to deduplicate the code for returning. + * @param cmd the command cost to return. + */ +#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; + } + + 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 0000000000..3369475675 --- /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 CcPlaySound_SPLAT_WATER; + +/* 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 CcPlaySound_EXPLOSION; +CommandCallback CcPlaceSign; +CommandCallback CcTerraform; +CommandCallback CcGiveMoney; + +/* rail_gui.cpp */ +CommandCallback CcPlaySound_SPLAT_RAIL; +CommandCallback CcRailDepot; +CommandCallback CcStation; +CommandCallback CcBuildRailTunnel; + +/* road_gui.cpp */ +CommandCallback CcPlaySound_SPLAT_OTHER; +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 0000000000..f644d654cc --- /dev/null +++ b/src/command_type.h @@ -0,0 +1,484 @@ +/* $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_SCROLL_VIEWPORT, ///< scroll main viewport of players + + 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_SET_GROUP_LIVERY, ///< set the livery 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_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, uint32 cmd); + +/** + * 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 0000000000..9d2bc90009 --- /dev/null +++ b/src/company_base.h @@ -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 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. + StringID name_1; ///< Name of the company if the user did not change it. + char *name; ///< Name of the company if the user changed it. + + StringID 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. + + 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 #ExpensesType 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. + + // TODO: Change some of these member variables to use relevant INVALID_xxx constants + CompanyProperties() + : name_2(0), name_1(0), name(NULL), president_name_1(0), president_name_2(0), president_name(NULL), + face(0), money(0), money_fraction(0), current_loan(0), colour(0), block_preview(0), + location_of_HQ(0), last_build_coordinate(0), share_owners(), inaugurated_year(0), + months_of_bankruptcy(0), bankrupt_asked(0), bankrupt_timeout(0), bankrupt_value(0), + terraform_limit(0), clear_limit(0), tree_limit(0), is_ai(false) {} + + ~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]; + RailTypes avail_railtypes; ///< Rail types available to this company. + 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 0000000000..62a818ea62 --- /dev/null +++ b/src/company_cmd.cpp @@ -0,0 +1,1172 @@ +/* $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); +} + +/** 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); +} + +/** + * 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); + + /* If actually changing to another company, several windows need closing */ + bool switching_company = _local_company != new_company; + +#ifdef ENABLE_NETWORK + /* Delete the chat window, if you were team chatting. */ + if (switching_company) InvalidateWindowData(WC_SEND_NETWORK_MSG, DESTTYPE_TEAM, _local_company); +#endif + + assert(IsLocalCompany()); + + _current_company = _local_company = new_company; + + /* Delete any construction windows... */ + if (switching_company) 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: + 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[in,out] cost 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, 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, 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 = 0; + c->livery[scheme].colour1 = c->colour; + c->livery[scheme].colour2 = c->colour; + } + + Group *g; + FOR_ALL_GROUPS(g) { + if (g->owner == c->index) { + g->livery.in_use = 0; + g->livery.colour1 = c->colour; + g->livery.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)); + + 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, CCA_NEW_AI | 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: CompanyCtrlAction + * - bits 16..23: CompanyID + * - bits 24..31: CompanyRemoveReason (with CCA_DELETE) + * @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); + + switch ((CompanyCtrlAction)GB(p1, 0, 16)) { + case CCA_NEW: { // 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(); + + ClientID client_id = (ClientID)p2; + 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 CCA_NEW_AI: { // 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 CCA_DELETE: { // Delete a company + CompanyRemoveReason reason = (CompanyRemoveReason)GB(p1, 24, 8); + 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 bit 8 set 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); + bool second = HasBit(p1, 8); + + if (scheme >= LS_END || (colour >= COLOUR_END && colour != INVALID_COLOUR)) return CMD_ERROR; + + /* Default scheme can't be reset to invalid. */ + if (scheme == LS_DEFAULT && 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 && !second) { + const Company *cc; + FOR_ALL_COMPANIES(cc) { + if (cc != c && cc->colour == colour) return CMD_ERROR; + } + } + + if (flags & DC_EXEC) { + if (!second) { + if (scheme != LS_DEFAULT) SB(c->livery[scheme].in_use, 0, 1, colour != INVALID_COLOUR); + if (colour == INVALID_COLOUR) colour = (Colours)c->livery[LS_DEFAULT].colour1; + 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) { + for (int i = 1; i < LS_END; i++) { + if (!HasBit(c->livery[i].in_use, 0)) c->livery[i].colour1 = colour; + } + _company_colours[_current_company] = colour; + c->colour = colour; + CompanyAdminUpdate(c); + } + } else { + if (scheme != LS_DEFAULT) SB(c->livery[scheme].in_use, 1, 1, colour != INVALID_COLOUR); + if (colour == INVALID_COLOUR) colour = (Colours)c->livery[LS_DEFAULT].colour2; + c->livery[scheme].colour2 = colour; + + if (scheme == LS_DEFAULT) { + for (int i = 1; i < LS_END; i++) { + if (!HasBit(c->livery[i].in_use, 1)) c->livery[i].colour2 = colour; + } + } + } + + if (c->livery[scheme].in_use != 0) { + /* If enabling a scheme, set the default scheme to be in use too */ + c->livery[LS_DEFAULT].in_use = 1; + } else { + /* 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 = 0; + for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) { + if (c->livery[scheme].in_use != 0) { + c->livery[LS_DEFAULT].in_use = 1; + 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 0000000000..29650d78cd --- /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 0000000000..a3885ec960 --- /dev/null +++ b/src/company_gui.cpp @@ -0,0 +1,2822 @@ +/* $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 "sortlist_type.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_OTHER, +}; + +/** Grouped list of expenses. */ +static ExpensesType _expenses_list_2[] = { + EXPENSES_TRAIN_INC, + EXPENSES_ROADVEH_INC, + EXPENSES_AIRCRAFT_INC, + EXPENSES_SHIP_INC, + INVALID_EXPENSES, + EXPENSES_TRAIN_RUN, + EXPENSES_ROADVEH_RUN, + EXPENSES_AIRCRAFT_RUN, + EXPENSES_SHIP_RUN, + 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. */ +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(); + FALLTHROUGH; + + 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 this->result >= COLOUR_END ? STR_COLOUR_DEFAULT : _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 % COLOUR_END), + 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); + } +}; + +static const int LEVEL_WIDTH = 10; ///< Indenting width of a sub-group in pixels + +typedef GUIList GUIGroupList; + +/** Company livery colour scheme window. */ +struct SelectCompanyLiveryWindow : public Window { +private: + uint32 sel; + LiveryClass livery_class; + Dimension square; + uint rows; + uint line_height; + GUIGroupList groups; + SmallVector indents; + Scrollbar *vscroll; + + void ShowColourDropDownMenu(uint32 widget) + { + uint32 used_colours = 0; + const Company *c; + const Livery *livery, *default_livery = NULL; + bool primary = widget == WID_SCL_PRI_COL_DROPDOWN; + byte default_col; + + /* Disallow other company colours for the primary colour */ + if (this->livery_class < LC_GROUP_RAIL && HasBit(this->sel, LS_DEFAULT) && primary) { + FOR_ALL_COMPANIES(c) { + if (c->index != _local_company) SetBit(used_colours, c->colour); + } + } + + c = Company::Get((CompanyID)this->window_number); + + if (this->livery_class < LC_GROUP_RAIL) { + /* Get the first selected livery to use as the default dropdown item */ + LiveryScheme scheme; + for (scheme = LS_BEGIN; scheme < LS_END; scheme++) { + if (HasBit(this->sel, scheme)) break; + } + if (scheme == LS_END) scheme = LS_DEFAULT; + livery = &c->livery[scheme]; + if (scheme != LS_DEFAULT) default_livery = &c->livery[LS_DEFAULT]; + } else { + const Group *g = Group::Get(this->sel); + livery = &g->livery; + if (g->parent == INVALID_GROUP) { + default_livery = &c->livery[LS_DEFAULT]; + } else { + const Group *pg = Group::Get(g->parent); + default_livery = &pg->livery; + } + } + + DropDownList *list = new DropDownList(); + if (default_livery != NULL) { + /* Add COLOUR_END to put the colour out of range, but also allow us to show what the default is */ + default_col = (primary ? default_livery->colour1 : default_livery->colour2) + COLOUR_END; + *list->Append() = new DropDownListColourItem(default_col, false); + } + for (uint i = 0; i < lengthof(_colour_dropdown); i++) { + *list->Append() = new DropDownListColourItem(i, HasBit(used_colours, i)); + } + + byte sel = (default_livery == NULL || HasBit(livery->in_use, primary ? 0 : 1)) ? (primary ? livery->colour1 : livery->colour2) : default_col; + ShowDropDownList(this, list, sel, widget); + } + + static int CDECL GroupNameSorter(const Group * const *a, const Group * const *b) + { + static const Group *last_group[2] = { NULL, NULL }; + static char last_name[2][64] = { "", "" }; + + if (*a != last_group[0]) { + last_group[0] = *a; + SetDParam(0, (*a)->index); + GetString(last_name[0], STR_GROUP_NAME, lastof(last_name[0])); + } + + if (*b != last_group[1]) { + last_group[1] = *b; + SetDParam(0, (*b)->index); + GetString(last_name[1], STR_GROUP_NAME, lastof(last_name[1])); + } + + int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting). + if (r == 0) return (*a)->index - (*b)->index; + return r; + } + + void AddChildren(GUIGroupList *source, GroupID parent, int indent) + { + for (const Group **g = source->Begin(); g != source->End(); g++) { + if ((*g)->parent != parent) continue; + *this->groups.Append() = *g; + *this->indents.Append() = indent; + AddChildren(source, (*g)->index, indent + 1); + } + } + + void BuildGroupList(CompanyID owner) + { + if (!this->groups.NeedRebuild()) return; + + this->groups.Clear(); + this->indents.Clear(); + + if (this->livery_class >= LC_GROUP_RAIL) { + GUIGroupList list; + VehicleType vtype = (VehicleType)(this->livery_class - LC_GROUP_RAIL); + + const Group *g; + FOR_ALL_GROUPS(g) { + if (g->owner == owner && g->vehicle_type == vtype) { + *list.Append() = g; + } + } + + list.ForceResort(); + list.Sort(&GroupNameSorter); + + AddChildren(&list, INVALID_GROUP, 0); + } + + this->groups.Compact(); + this->groups.RebuildDone(); + } + + void SetRows() + { + if (this->livery_class < LC_GROUP_RAIL) { + this->rows = 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->rows++; + } + } + } else { + this->rows = this->groups.Length(); + } + + this->vscroll->SetCount(this->rows); + } + +public: + SelectCompanyLiveryWindow(WindowDesc *desc, CompanyID company, GroupID group) : Window(desc) + { + this->CreateNestedTree(); + this->vscroll = this->GetScrollbar(WID_SCL_MATRIX_SCROLLBAR); + + if (group == INVALID_GROUP) { + this->livery_class = LC_OTHER; + this->sel = 1; + this->LowerWidget(WID_SCL_CLASS_GENERAL); + this->BuildGroupList(company); + this->SetRows(); + } else { + this->SetSelectedGroup(company, group); + } + + this->FinishInitNested(company); + this->owner = company; + this->InvalidateData(1); + } + + void SetSelectedGroup(CompanyID company, GroupID group) + { + this->RaiseWidget(this->livery_class + WID_SCL_CLASS_GENERAL); + const Group *g = Group::Get(group); + switch (g->vehicle_type) { + case VEH_TRAIN: this->livery_class = LC_GROUP_RAIL; break; + case VEH_ROAD: this->livery_class = LC_GROUP_ROAD; break; + case VEH_SHIP: this->livery_class = LC_GROUP_SHIP; break; + case VEH_AIRCRAFT: this->livery_class = LC_GROUP_AIRCRAFT; break; + default: NOT_REACHED(); + } + this->sel = group; + this->LowerWidget(this->livery_class + WID_SCL_CLASS_GENERAL); + + this->groups.ForceRebuild(); + this->BuildGroupList(company); + this->SetRows(); + + /* Position scrollbar to selected group */ + for (uint i = 0; i < this->rows; i++) { + if (this->groups[i]->index == sel) { + this->vscroll->SetPosition(Clamp(i - this->vscroll->GetCapacity() / 2, 0, max(this->vscroll->GetCount() - this->vscroll->GetCapacity(), 0))); + break; + } + } + } + + 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)); + } + + /* And group names */ + const Group *g; + FOR_ALL_GROUPS(g) { + if (g->owner == (CompanyID)this->window_number) { + SetDParam(0, g->index); + d = maxdim(d, GetStringBoundingBox(STR_GROUP_NAME)); + } + } + + size->width = max(size->width, 5 + d.width + WD_FRAMERECT_RIGHT); + break; + } + + case WID_SCL_MATRIX: { + /* 11 items in the default rail class */ + this->square = GetSpriteSize(SPR_SQUARE); + this->line_height = max(this->square.height, (uint)FONT_HEIGHT_NORMAL) + 4; + + size->height = 11 * this->line_height; + resize->width = 1; + resize->height = this->line_height; + break; + } + + case WID_SCL_SEC_COL_DROPDOWN: + if (!_loaded_newgrf_features.has_2CC) { + size->width = 0; + break; + } + FALLTHROUGH; + + case WID_SCL_PRI_COL_DROPDOWN: { + this->square = GetSpriteSize(SPR_SQUARE); + 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); + } + size->width = max(size->width, GetStringBoundingBox(STR_COLOUR_DEFAULT).width + padding); + break; + } + } + } + + virtual void OnPaint() + { + bool local = (CompanyID)this->window_number == _local_company; + + /* Disable dropdown controls if no scheme is selected */ + bool disabled = this->livery_class < LC_GROUP_RAIL ? (this->sel == 0) : (this->sel == INVALID_GROUP); + this->SetWidgetDisabledState(WID_SCL_PRI_COL_DROPDOWN, !local || disabled); + this->SetWidgetDisabledState(WID_SCL_SEC_COL_DROPDOWN, !local || disabled); + + this->BuildGroupList((CompanyID)this->window_number); + + this->DrawWidgets(); + } + + virtual void SetStringParameters(int widget) const + { + switch (widget) { + case WID_SCL_CAPTION: + SetDParam(0, (CompanyID)this->window_number); + break; + + case WID_SCL_PRI_COL_DROPDOWN: + case WID_SCL_SEC_COL_DROPDOWN: { + const Company *c = Company::Get((CompanyID)this->window_number); + bool primary = widget == WID_SCL_PRI_COL_DROPDOWN; + StringID colour = STR_COLOUR_DEFAULT; + + if (this->livery_class < LC_GROUP_RAIL) { + if (this->sel != 0) { + LiveryScheme scheme = LS_DEFAULT; + for (scheme = LS_BEGIN; scheme < LS_END; scheme++) { + if (HasBit(this->sel, scheme)) break; + } + if (scheme == LS_END) scheme = LS_DEFAULT; + const Livery *livery = &c->livery[scheme]; + if (scheme == LS_DEFAULT || HasBit(livery->in_use, primary ? 0 : 1)) { + colour = STR_COLOUR_DARK_BLUE + (primary ? livery->colour1 : livery->colour2); + } + } + } else { + if (this->sel != INVALID_GROUP) { + const Group *g = Group::Get(this->sel); + const Livery *livery = &g->livery; + if (HasBit(livery->in_use, primary ? 0 : 1)) { + colour = STR_COLOUR_DARK_BLUE + (primary ? livery->colour1 : livery->colour2); + } + } + } + SetDParam(0, colour); + 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->square.width + 5)); + int text_right = (rtl ? (this->square.width + 5) : (uint)WD_FRAMERECT_RIGHT); + + 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; + + /* Helper function to draw livery info. */ + auto draw_livery = [&](StringID str, const Livery &liv, bool sel, bool def, int indent) { + /* Livery Label. */ + DrawString(sch_left + WD_FRAMERECT_LEFT + (rtl ? 0 : indent), sch_right - WD_FRAMERECT_RIGHT - (rtl ? indent : 0), y + text_offs, str, sel ? TC_WHITE : TC_BLACK); + + /* Text below the first dropdown. */ + DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOUR(liv.colour1), (rtl ? pri_right - (this->square.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, (def || HasBit(liv.in_use, 0)) ? STR_COLOUR_DARK_BLUE + liv.colour1 : STR_COLOUR_DEFAULT, 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(liv.colour2), (rtl ? sec_right - (this->square.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, (def || HasBit(liv.in_use, 1)) ? STR_COLOUR_DARK_BLUE + liv.colour2 : STR_COLOUR_DEFAULT, sel ? TC_WHITE : TC_GOLD); + } + + y += this->line_height; + }; + + if (livery_class < LC_GROUP_RAIL) { + int pos = this->vscroll->GetPosition(); + 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)) { + if (pos-- > 0) continue; + draw_livery(STR_LIVERY_DEFAULT + scheme, c->livery[scheme], HasBit(this->sel, scheme), scheme == LS_DEFAULT, 0); + } + } + } else { + uint max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->groups.Length()); + for (uint i = this->vscroll->GetPosition(); i < max; ++i) { + const Group *g = this->groups[i]; + SetDParam(0, g->index); + draw_livery(STR_GROUP_NAME, g->livery, this->sel == g->index, false, this->indents[i] * LEVEL_WIDTH); + } + } + } + + 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: + case WID_SCL_GROUPS_RAIL: + case WID_SCL_GROUPS_ROAD: + case WID_SCL_GROUPS_SHIP: + case WID_SCL_GROUPS_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 */ + if (this->livery_class < LC_GROUP_RAIL) { + 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; + } + } + } else { + this->sel = INVALID_GROUP; + this->groups.ForceRebuild(); + this->BuildGroupList((CompanyID)this->window_number); + + if (this->groups.Length() > 0) { + this->sel = this->groups[0]->index; + } + } + + this->SetRows(); + this->SetDirty(); + 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: { + uint row = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SCL_MATRIX, 0, this->line_height); + if (row >= this->rows) return; + + if (this->livery_class < LC_GROUP_RAIL) { + LiveryScheme j = (LiveryScheme)row; + + for (LiveryScheme scheme = LS_BEGIN; scheme <= j && scheme < LS_END; scheme++) { + if (_livery_class[scheme] != this->livery_class || !HasBit(_loaded_newgrf_features.used_liveries, scheme)) j++; + } + assert(j < LS_END); + + if (_ctrl_pressed) { + ToggleBit(this->sel, j); + } else { + this->sel = 1 << j; + } + } else { + this->sel = this->groups[row]->index; + } + this->SetDirty(); + break; + } + } + } + + virtual void OnResize() + { + this->vscroll->SetCapacityFromWidget(this, WID_SCL_MATRIX); + } + + virtual void OnDropdownSelect(int widget, int index) + { + bool local = (CompanyID)this->window_number == _local_company; + if (!local) return; + + if (index >= COLOUR_END) index = INVALID_COLOUR; + + if (this->livery_class < LC_GROUP_RAIL) { + /* Set company colour livery */ + 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); + } + } + } else { + /* Setting group livery */ + DoCommandP(0, this->sel, (widget == WID_SCL_PRI_COL_DROPDOWN ? 0 : 256) | (index << 16), CMD_SET_GROUP_LIVERY); + } + } + + /** + * 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 (data != -1) { + /* data contains a VehicleType, rebuild list if it displayed */ + if (this->livery_class == data + LC_GROUP_RAIL) { + this->groups.ForceRebuild(); + this->BuildGroupList((CompanyID)this->window_number); + this->SetRows(); + + if (!Group::IsValidID(this->sel)) { + this->sel = INVALID_GROUP; + if (this->groups.Length() > 0) this->sel = this->groups[0]->index; + } + + this->SetDirty(); + } + 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 || this->livery_class >= LC_GROUP_RAIL; + 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 if (this->livery_class < LC_GROUP_RAIL) { + ClrBit(this->sel, scheme); + } + } + } + + if (!current_class_valid) { + Point pt = {0, 0}; + this->OnClick(pt, WID_SCL_CLASS_GENERAL, 1); + } + } +}; + +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_IMGBTN, COLOUR_GREY, WID_SCL_GROUPS_RAIL), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_GROUP_LIVERY_TRAIN, STR_LIVERY_TRAIN_TOOLTIP), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_GROUPS_ROAD), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_GROUP_LIVERY_ROADVEH, STR_LIVERY_ROAD_VEHICLE_TOOLTIP), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_GROUPS_SHIP), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_GROUP_LIVERY_SHIP, STR_LIVERY_SHIP_TOOLTIP), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_GROUPS_AIRCRAFT), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_GROUP_LIVERY_AIRCRAFT, 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(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_SCL_MATRIX), SetMinimalSize(275, 0), SetResize(1, 0), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_LIVERY_PANEL_TOOLTIP), SetScrollbar(WID_SCL_MATRIX_SCROLLBAR), + NWidget(NWID_VERTICAL), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SCL_MATRIX_SCROLLBAR), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), + EndContainer(), +}; + +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) +); + +void ShowCompanyLiveryWindow(CompanyID company, GroupID group) +{ + SelectCompanyLiveryWindow *w = (SelectCompanyLiveryWindow *)BringWindowToFrontById(WC_COMPANY_COLOUR, company); + if (w == NULL) { + new SelectCompanyLiveryWindow(&_select_company_livery_desc, company, group); + } else if (group != INVALID_GROUP) { + w->SetSelectedGroup(company, group); + } +} + +/** + * 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: + 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); + FALLTHROUGH; + + /* 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 + */ +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_pieces = c->infrastructure.signal; + uint road_pieces = 0; + for (uint i = 0; i < lengthof(c->infrastructure.rail); i++) rail_pieces += c->infrastructure.rail[i]; + for (uint i = 0; i < lengthof(c->infrastructure.road); i++) road_pieces += c->infrastructure.road[i]; + + if (rail_pieces == 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_pieces != 0) { + SetDParam(0, rail_pieces); + 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: + ShowCompanyLiveryWindow((CompanyID)this->window_number, INVALID_GROUP); + 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)) && !_shift_pressed) { + 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 0000000000..c5593d15d3 --- /dev/null +++ b/src/company_gui.h @@ -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 company_gui.h GUI Functions related to companies. */ + +#ifndef COMPANY_GUI_H +#define COMPANY_GUI_H + +#include "company_type.h" +#include "group.h" +#include "gfx_type.h" + +TextColour GetDrawStringCompanyColour(CompanyID company); +void DrawCompanyIcon(CompanyID c, int x, int y); + +void ShowCompanyLiveryWindow(CompanyID company, GroupID group); +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 0000000000..511f85b7d5 --- /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, 5 }, { 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 0000000000..771e6d8b93 --- /dev/null +++ b/src/company_type.h @@ -0,0 +1,76 @@ +/* $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. +}; + +/** The action to do with CMD_COMPANY_CTRL. */ +enum CompanyCtrlAction { + CCA_NEW, ///< Create a new company. + CCA_NEW_AI, ///< Create a new AI company. + CCA_DELETE, ///< Delete a company. + + CCA_END, ///< Sentinel for end. +}; + +#endif /* COMPANY_TYPE_H */ diff --git a/src/console.cpp b/src/console.cpp new file mode 100644 index 0000000000..2cf9d96958 --- /dev/null +++ b/src/console.cpp @@ -0,0 +1,520 @@ +/* $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[in,out] name String to remove the underscores from. + * @return \a name, with its contents modified. + */ +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 (tstream_i >= lengthof(tokenstream)) { + IConsoleError("command line too long"); + return; + } + + 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) { + if (t_index >= lengthof(tokens)) { + IConsoleError("command line too long"); + return; + } + 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; + } + FALLTHROUGH; + default: // Normal character + tokenstream[tstream_i++] = *cmdptr; + + if (!foundtoken) { + if (t_index >= lengthof(tokens)) { + IConsoleError("command line too long"); + return; + } + tokens[t_index++] = &tokenstream[tstream_i - 1]; + foundtoken = true; + } + break; + } + } + + for (uint i = 0; i < lengthof(tokens) && 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 0000000000..298fd4f98d --- /dev/null +++ b/src/console_cmds.cpp @@ -0,0 +1,2064 @@ +/* $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). + +/** File list storage for the console, for caching the last 'ls' command. */ +class ConsoleFileList : public FileList { +public: + ConsoleFileList() : FileList() + { + this->file_list_valid = false; + } + + /** Declare the file storage cache as being invalid, also clears all stored files. */ + void InvalidateFileList() + { + this->Clear(); + this->file_list_valid = false; + } + + /** + * (Re-)validate the file storage cache. Only makes a change if the storage was invalid, or if \a force_reload. + * @param force_reload Always reload the file storage cache. + */ + void ValidateFileList(bool force_reload = false) + { + if (force_reload || !this->file_list_valid) { + this->BuildFileList(FT_SAVEGAME, SLO_LOAD); + this->file_list_valid = true; + } + } + + bool file_list_valid; ///< If set, the file list is valid. +}; + +static ConsoleFileList _console_file_list; ///< File storage cache for the console. + +/* 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 x tile number or tile x coordinate. + * param y optional 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, SLO_SAVE, DFT_GAME_FILE, 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; +} + +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]; + _console_file_list.ValidateFileList(); + const FiosItem *item = _console_file_list.FindItem(file); + if (item != NULL) { + if (GetAbstractFileType(item->type) == FT_SAVEGAME) { + _switch_mode = SM_LOAD_GAME; + _file_to_saveload.SetMode(item->type); + _file_to_saveload.SetName(FiosBrowseTo(item)); + _file_to_saveload.SetTitle(item->title); + } else { + IConsolePrintF(CC_ERROR, "%s: Not a savegame.", file); + } + } else { + IConsolePrintF(CC_ERROR, "%s: No such file or directory.", file); + } + + 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]; + _console_file_list.ValidateFileList(); + const FiosItem *item = _console_file_list.FindItem(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); + } + + _console_file_list.InvalidateFileList(); + 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; + } + + _console_file_list.ValidateFileList(true); + for (uint i = 0; i < _console_file_list.Length(); i++) { + IConsolePrintF(CC_DEFAULT, "%d) %s", i, _console_file_list[i].title); + } + + 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]; + _console_file_list.ValidateFileList(true); + const FiosItem *item = _console_file_list.FindItem(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); + } + + _console_file_list.InvalidateFileList(); + 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 */ + _console_file_list.ValidateFileList(true); + _console_file_list.InvalidateFileList(); + + 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; + + /* Try by IP. */ + uint index; + for (index = 0; index < _network_ban_list.Length(); index++) { + if (strcmp(_network_ban_list[index], argv[1]) == 0) break; + } + + /* Try by index. */ + if (index >= _network_ban_list.Length()) { + index = atoi(argv[1]) - 1U; // let it wrap + } + + if (index < _network_ban_list.Length()) { + char msg[64]; + seprintf(msg, lastof(msg), "Unbanned %s", _network_ban_list[index]); + IConsolePrint(CC_DEFAULT, msg); + free(_network_ban_list[index]); + _network_ban_list.Erase(_network_ban_list.Get(index)); + } else { + IConsolePrint(CC_DEFAULT, "Invalid list index or IP not in ban-list."); + IConsolePrint(CC_DEFAULT, "For a list of banned IP's, see the command 'banlist'"); + } + + 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, CCA_DELETE | index << 16 | CRR_MANUAL << 24, 0, 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

    -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 literal 0 HcmV?d00001 diff --git a/media/extra_grf/sloped_tracks.nfo b/media/extra_grf/sloped_tracks.nfo new file mode 100644 index 0000000000..ed17bc8445 --- /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 0000000000000000000000000000000000000000..16ace38c540ff03327c765f7b50ac228ae12a67a GIT binary patch literal 2495 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. +// + -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 0000000000000000000000000000000000000000..5e21455bc49d76d912893116bfb1cc27783b9f6e GIT binary patch literal 25946 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 literal 0 HcmV?d00001 diff --git a/media/extra_grf/tunnel_portals.nfo b/media/extra_grf/tunnel_portals.nfo new file mode 100644 index 0000000000..711229aab5 --- /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 0000000000000000000000000000000000000000..00abd9c7ffbcc5fb7805695f83e2841339aff376 GIT binary patch literal 18680 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

  • Landscape

    pz*KqTf!u@ARzn>7rLl*~3CZIoLv3 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 z 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 literal 0 HcmV?d00001 diff --git a/bin/baseset/orig_extra.grf b/bin/baseset/orig_extra.grf new file mode 100644 index 0000000000000000000000000000000000000000..728a8b2555bb3de7506193ed1124209dafa33ad7 GIT binary patch literal 328676 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 xuVn$B_X1wa@. + */ + +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); +} + +/* 1.9 adds a vehicle type parameter. */ +GSBridge._GetName <- GSBridge.GetName; +GSBridge.GetName <- function(bridge_id) +{ + return GSBridge._GetName(bridge_id, GSVehicle.VT_RAIL); +} diff --git a/bin/game/compat_1.3.nut b/bin/game/compat_1.3.nut new file mode 100644 index 0000000000..0d7a2afb60 --- /dev/null +++ b/bin/game/compat_1.3.nut @@ -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 . + */ + +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); +} + +/* 1.9 adds a vehicle type parameter. */ +GSBridge._GetName <- GSBridge.GetName; +GSBridge.GetName <- function(bridge_id) +{ + return GSBridge._GetName(bridge_id, GSVehicle.VT_RAIL); +} diff --git a/bin/game/compat_1.4.nut b/bin/game/compat_1.4.nut new file mode 100644 index 0000000000..3ff887727e --- /dev/null +++ b/bin/game/compat_1.4.nut @@ -0,0 +1,24 @@ +/* $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); +} + +/* 1.9 adds a vehicle type parameter. */ +GSBridge._GetName <- GSBridge.GetName; +GSBridge.GetName <- function(bridge_id) +{ + return GSBridge._GetName(bridge_id, GSVehicle.VT_RAIL); +} diff --git a/bin/game/compat_1.5.nut b/bin/game/compat_1.5.nut new file mode 100644 index 0000000000..b29a8ed2f3 --- /dev/null +++ b/bin/game/compat_1.5.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.5 API compatibility in effect."); + +/* 1.9 adds a vehicle type parameter. */ +GSBridge._GetName <- GSBridge.GetName; +GSBridge.GetName <- function(bridge_id) +{ + return GSBridge._GetName(bridge_id, GSVehicle.VT_RAIL); +} diff --git a/bin/game/compat_1.6.nut b/bin/game/compat_1.6.nut new file mode 100644 index 0000000000..a3f5975287 --- /dev/null +++ b/bin/game/compat_1.6.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.6 API compatibility in effect."); + +/* 1.9 adds a vehicle type parameter. */ +GSBridge._GetName <- GSBridge.GetName; +GSBridge.GetName <- function(bridge_id) +{ + return GSBridge._GetName(bridge_id, GSVehicle.VT_RAIL); +} diff --git a/bin/game/compat_1.7.nut b/bin/game/compat_1.7.nut new file mode 100644 index 0000000000..b4c4d1bb35 --- /dev/null +++ b/bin/game/compat_1.7.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.7 API compatibility in effect."); + +/* 1.9 adds a vehicle type parameter. */ +GSBridge._GetName <- GSBridge.GetName; +GSBridge.GetName <- function(bridge_id) +{ + return GSBridge._GetName(bridge_id, GSVehicle.VT_RAIL); +} diff --git a/bin/game/compat_1.8.nut b/bin/game/compat_1.8.nut new file mode 100644 index 0000000000..5aac3f8c1d --- /dev/null +++ b/bin/game/compat_1.8.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.8 API compatibility in effect."); + +/* 1.9 adds a vehicle type parameter. */ +GSBridge._GetName <- GSBridge.GetName; +GSBridge.GetName <- function(bridge_id) +{ + return GSBridge._GetName(bridge_id, GSVehicle.VT_RAIL); +} diff --git a/bin/game/compat_1.9.nut b/bin/game/compat_1.9.nut new file mode 100644 index 0000000000..fe985b90d0 --- /dev/null +++ b/bin/game/compat_1.9.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 0000000000..af1b66d213 --- /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 0000000000..5a36201410 --- /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 0000000000..5bbd760492 --- /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 0000000000..5465cd7978 --- /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 0000000000..cc799d9e7e --- /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 0000000000..233cf1b4e2 --- /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 0000000000..b41ca51d2d --- /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 0000000000..c1b6c822c5 --- /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 0000000000..8f13e74e98 --- /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 0000000000..cd9bbe7ebe --- /dev/null +++ b/changelog.txt @@ -0,0 +1,5810 @@ +1.9.3 (2019-09-16) +------------------------------------------------------------------------ +- Change: Use natural sort when sorting the file list (#7727) +- Fix #7479: Don't close construction windows when changing client name (#7728) +- Fix #7731: Files sorting by modification time on Windows XP (#7731) +- Fix #7644: [OSX] Better solution for colourspace/performance issues (#7741) + + +1.9.3-RC1 (2019-09-07) +------------------------------------------------------------------------ +- Add: Can now click industries to make orders to their neutral station (e.g. oil rig) (#7709) +- Fix #7644: [OSX] Poor framerate on certain systems (#7721) +- Fix #7702: Highscore screen UI scaling (#7714) +- Fix #7704: [OSX] Handle malformed UTF8 strings, leading to crashes in server browser (#7705) +- Fix #7188: [AI] Possible crash when reloading an AI in multiplayer games (#7701, #7725) +- Fix: RemoveAirport function now returns 'Aircraft in the way' error message when occupied (#7690) +- Fix: Spelling in running costs setting help text (#7686) +- Fix #7655: 'Decrease' buttons in cheat window not working properly with UI scaling (#7669) +- Fix: [GS] Could not create elements on Storybook pages with ID > 255 (#7657) +- Fix #7626: Allow building road stops over town-owned one-way roads, instead of crashing (#7627) + + +1.9.2 (2019-07-07) +------------------------------------------------------------------------ +- Change: Set default setting in server browser of "Advertised" to "Yes" (#7568) +- Change: Allow building road stops over self-owned one-way/blocked road (#7547) +- Fix #7463: Promote scroll mode setting to basic category (#7586) +- Fix: Inconsistent GUI scaling (#7539) +- Fix #7491: Send company update admin message when bankruptcy counter changes (#7492) +- Fix #7553: Check bounds when loading strings (#7554) +- Fix: Really increase the maximum number of GameScript texts to 64k (#7555) +- Fix: Crash when attempting to load old save game with GRFs set (#7546) +- Fix #6507: Don't try to load invalid depots from older savegames (#7546) +- Fix: Railtype bits were moved too late, leading to rails under bridges losing their type (#7546) +- Fix: Bounds check access to railtype_map (#7529) +- Fix: Spurious errors when using more than 32 railtypes (#7533) +- Fix #7633: Allow zero-cost track conversion to succeed (#7634) +- Fix #7577: Check if linkgraph station index is valid before dereferencing (#7583) +- Fix #7224: Drag and drop vehicle group creation does not work correctly (#7581) +- Fix #7570: Show Github URL in the crashlog window (#7571) +- Fix: Clicking on scrollbar 'thumb' moved position up instantly (#7549) +- Fix #7255: Prevent crashlog corruption by only printing the 32 most recent news messages (#7542) +- Fix #5685: Check for free wagons in ScriptVehicleList (#7617) +- Fix: Make GSGoal.QuestionClient work correctly at least for clients with ID < 2**16 (#7560) +- Fix #6666: Mismatched parentheses in RTL languages (#7480) +- Fix: [Windows] Various reliability and correctness improvements to MIDI on Windows (#7620) + + +1.9.1 (2019-04-08) +------------------------------------------------------------------------ +- Fix #6564: Enforce types of arguments for station name strings (#7419) +- Fix #7433: Don't use AirportSpec substitute if it's not enabled (#7435) +- Fix #7447, #7466, #7476: Missing NewGRF strings due to Action 4 feature check skipping pseudo-feature 48 (#7449) +- Fix #6222: Advanced sprite layout sometimes showed incorrect railtype ground tile. (#7460) +- Fix #7439: CompanyRemoveReason overwritten by ClientID (#7465) +- Fix: [Windows] Incorrect error handling could lead to cascading error windows (#7482) +- Fix #7478: Don't remove NewGRF objects on company take-over. (#7483) + + +1.9.0 (2019-04-01) +------------------------------------------------------------------------ +- Fix #7411: Use industry production callback (if used) on initial industry cargo generation (#7412) + + +1.9.0-RC2 (2019-03-24) +------------------------------------------------------------------------ +- Fix #7400: WaterClass for tree tiles was not converted for old saves preventing industry creation (#7405) +- Fix: Filtered file list did not scroll properly (#7402) +- Fix #7391: Don't invalidate go to depot orders of non-aircraft when invalidating hangar orders that happen to share IDs (#7392) +- Fix #7386: Measurement tooltip for tunnels, aqueducts & docks did not display or flickered (#7389) +- Fix: Wrong company performance rating when money exceeds INT_MAX (#7382) +- Fix: Permit loading of industry production callback with invalid cargo type (#7364) +- Fix: Spelling for a few real town names (#7338) +- Fix: Runway too short for large aircraft message should not depend on plane crashes setting (#7325) +- Fix #7334: Ship lost after crossing bridge due to path cache not being consumed while on final bridge end (#7335) + + +1.9.0-RC1 (2019-03-03) +------------------------------------------------------------------------ +- Add: Various AI/GS functions for vehicle groups (#7225) +- Change: Synchronise introduction date and reliability randomness across vehicles with the same base introduction date (#7147) +- Change: Allow towns to build bridges over rails and one-way roads (#7291) +- Fix: Detection of coast tiles with trees on them (#7309) +- Fix: Emergency netsave saved the title game instead of the broken game in question (#7298) +- Fix: Company livery window showed incorrect groups when opened in multiplayer (#7288) +- Fix: Unable to select last group in open livery window (#7283) +- Fix: Goto hangar orders were not invalidated when rebuilding airports (#7100) + + +1.9.0-beta3 (2019-02-24) +------------------------------------------------------------------------ +- Feature: Option to adjust font size separately from GUI size (#7003) +- Feature: Increase maximum number of orders from 64000 to ~16.7m (#7220) +- Add: Show performance of AI and GS in framerate window +- Add: News menu entry and shortcut for deleting all messages (#7240) +- Change: [OSX] Improved scrolling behaviour when using touchpads +- Change: Add scrollbar to cargo legend in cargo payment rates window +- Change: Owner of vehicle with exclusive transport rights may now load cargo from neutral stations (#7256) +- Change: Improved UI behaviour when dragging sound volume sliders with the mouse (#7227) +- Change: Use selected vehicle group as parent when creating a new group (#7224) +- Change: Use SlErrorCorrupt() on pool index error when loading a savegame, instead of terminating (#7219) +- Change: Skip reliability decay if servicing is disabled +- Fix: Remove desert around lakes upon generation +- Fix: Re-sorting file list did not update filtered rows +- Fix #7159: Waiting time at red one-way signals was too short +- Fix #7189: Fluidsynth volume gain too high +- Fix #7004: Cargo flow legend was not properly refreshed after zooming (#7265) +- Fix: Possibility to modify wrong AI/GS settings when switching AI/GS scripts around (#7090, #7091) +- Fix: Use more descriptive "spectator" strings for story book and goal dropdown menus +- Fix #6599: Disable build and rename button in build vehicle window when no vehicle is selected +- Fix: Do not mangle tagged revision strings for network revision strings +- Fix #7151: AI start date deviation was still applied when not set to a random AI (#7223) +- Fix #7197: Invalidate depot buttons when necessary (#7212) +- Doc: [AI] UnshareOrders empties the orders list of the vehicle + + +1.9.0-beta2 (2019-02-09) +------------------------------------------------------------------------ +- Fix: Non-Windows builds did not get correct git hash + + +1.9.0-beta1 (2019-02-09) +------------------------------------------------------------------------ +Note: OpenTTD was migrated to GitHub for 1.9, so SVN revision and FlySpray numbers have been replaced with Pull Requests and Issue numbers +- Feature: Group liveries, and livery window usability enhancements (#7108) +- Feature: Overhaul of music system, support MPSMIDI music files (TTD DOS/TTO) (#6839) +- Feature: [Win32] Rewritten DMusic and WinMM music drivers +- Feature: [Win32] New XAudio2 sound driver +- Feature: [Linux] New Fluidsynth music driver +- Feature: Framerate display window (#6822) +- Feature: [NewGRF] Ability for industries & houses to produce and/or accept up to 16 different cargoes +- Feature #6610: Allow towns to build houses on road turns (#6758) +- Feature: Replace independent map scrolling GUI settings with single option, and add choice to not lock cursor position when scrolling (#6756) +- Feature #6459: API for querying network clients from GS (#6736) +- Feature: New Russian Ruble & Mexican Peso as currencies (#6678, #7035) +- Feature #4186: Append '(City)' after city names in the town directory +- Feature #986: Automatic save when losing connection to a network game +- Add: [NewGRF] Flag to hide rail types from construction (#7118) +- Add: [NewGRF] Airport animation trigger for plane landing (#6334) +- Add #4115: Default starting company colour setting (#6998) +- Add: Mixer feature for streaming sampled music +- Add #6460: [AI] start_date parameter for Random AIs on new game +- Add: BACKSPACE can be mapped as a hotkey +- Add: 32bpp SSE2 blitter palette animator (#6795) +- Change: Make ships turn slowly when changing direction and stop when going up or down a lock (#7065, #7150) +- Change: Improve ship pathfinder performance +- Change: Decouple GUI timing from game ticks (#6780) +- Change: Desert tiles are now half-desert if a neighboured tile is non-desert or sea/coast (#4754) +- Change: Gradually slow down aircraft speed on breakdown (#6932) +- Change: [NewGRF] Increase rail type & cargo type limits to 64 +- Change: [NewGRF] Increase size of persistent storage to 256 +- Change: [NewGRF] Use last OpenTTD SVN revision in NewGRF version number (#6843) +- Change: Clone tool in depot window now behaves like clone button in vehicle window (#6754) +- Change #6397: Keep town growth rate in sync with house count +- Change: Scale default FreeType font size selection by UI zoom level +- Change: [OSX] Reversed pinch to zoom behaviour +- Change: Switch town growth rate and counter to actual game ticks (#6763) +- Change: Non-tag revisions are now named '--g' +- Change: Rewrite several bits of documentation in markdown +- Fix: Reinitialise graph GUI on game restart (#7191) +- Fix: Potential crash during shutdown after unpacking downloaded content (#7185) +- Fix #6584: Text layout in engine preview dialogue +- Fix #6636: Airplanes could be sent to helicopter station depots +- Fix: Deadlock when launched with -n switch (#7103) +- Fix: Various corrections to town names in non-English languages (#7038, 7141) +- Fix: Only consider airport tiles when placing (for non-rectangular airports) (#6613) +- Fix: Spelling fixes on some Latin American town names +- Fix #7001: Pathfinders should see standard road stations as tiles where to reverse +- Fix #6676: Prevent helicopters from stopping in midair during some kinds of landing +- Fix: Remove need to use Ctrl+Click when building stations next to competitors (#6906) +- Fix: [NewGRF] Make VA2 operator 11 (ror) behave well-defined when rotating by 0 bits +- Fix #4109: Add more water checks to the Oil Rig layout +- Fix #6938: Incorrect value for "Cost to Clear" was displayed for Company Headquarters in tile inspector (#6939) +- Fix #6920: Make 9.8m/s^2 a common constant for TE-calculation +- Fix #6892: [Script] CONFIG_RANDOM did not use the full parameter range (#6902) +- Fix #6622: News message when GS constructs a town had empty company name +- Fix: [NewGRF] Action7 variable 0x85 had no bounds checks +- Fix #6875: Depot building cost did not include foundation build cost (#6883) +- Fix: Some pixels in ship autoreplace icon (sprite 106) were transparent +- Fix: Poor contrast in cargo dest flow legend window cargo labels +- Fix #6553: Make viewport button text unambiguous +- Fix: [OSX] Setting mouse-wheel to scroll the map does not disable pinch to zoom +- Fix #6969: Account for BOM when reading script files +- Fix #6898: Ability to use seeds above INT_MAX (#6936) +- Fix #6659: Bus stations could be demolished when not in demolish mode (#6815) +- Fix: One-way roads could be over-built by road stops regardless of road owner +- Fix: Use name of cargo instead of Passengers/Mail in town statistics (#6801) +- Fix: Prevent ships moving into docks after finishing (un)loading (#6791) +- Fix: Tractive effort was slightly too high as per NewGRF spec (#6785) +- Fix #6465: Add {NORMAL_FONT} and {MONO_FONT} control codes to GS strings (#6726) +- Fix: Four group action icons were misplaced and cropped +- Remove: PSP, WinCE support + + +1.8.0 (2018-04-01) +------------------------------------------------------------------------ +(None) + + +1.8.0-RC1 (2018-03-21) +------------------------------------------------------------------------ +- Feature: [GFX] Climate-specific Action5 extra airport sprites [FS#6664] (r27976) +- Feature: Draw vertical separators at tile distance in the train depot GUI (r27938, r27899) +- Feature: [Build] MSVC 2017 project file generator. Most noticeable, std:c++latest is enabled (r27920, r27919, r27918, r27917) +- Feature: [Build] Project file generator for kdevelop 4/5 [FS#6577] (r27897) +- Feature: Add option to close windows with right click [FS#4950] (r27826, r27825) +- Feature: Vehicle Group Info: Add profits and occupancy display to group vehicle list (r27822) +- Feature: Display aircraft type in vehicle preview/purchase/detail windows (r27802, r27799, r27797) +- Change: [NewGRF] Various performance improvements to resolving VA2 (r27989, r27985, r27984, r27983, r27982) +- Change: [NewGRF] Increase maximum allowed vehicle sprite size to reduce clipping of ships (r27987) +- Change: Check companies for bankruptcy before subtracting reoccuring monthly costs [FS#6679] (r27981) +- Change: [GFX] Replace the office building sprite on various toyland airports with a better fitting sprite [FS#6664] (r27977) +- Change: [GFX] The switch-toolbar icon contained pixels from the fire cycle. Replace the whole icon with a new version [FS#6654] (r27961) +- Change: Reword texts in industry view, when stockpiling is used (r27952) +- Change: Remove the gap between windows when positioning them after opening [FS#6568] (r27934, r27900) +- Change: [Build] Enable usage of static_assert for MSVC (r27916) +- Change: [Build] Preserve PKG_CONFIG_PATH and PKG_CONFIG_LIBDIR environment variables in config.cache file [FS#6614] (r27902) +- Change: Do not cancel headquarter construction and engine-preview-query when shift-clicking (r27889) +- Change: Parse extmidi command string for parameters to pass on (r27834) +- Change: Draw images in centre of buttons (r27829, r27821) +- Fix: Store the map variety setting in the savegame like the other mapgen settings, so restarting maps considers it [FS#6673] (r27978) +- Fix: Hair selection was missing one option [FS#6642] (r27975) +- Fix: Avoid tile operations outside map border when building lock [FS#6662] (r27973) +- Fix: Catenary sprites got mixed up for depots [FS#6670] (r27972) +- Fix: Make automatic window-positioning RTL-aware (r27934, r27900) +- Fix: Automatic window-positioning now uses GUI-scale/style dependent sizes/distances instead of fixed pixel values (r27934, r27900) +- Fix: [NewGRF] While executing random triggers, var 5F should include the new triggers (r27928) +- Fix: [NewGRF] Reset used random triggers only after all A123 chains have been resolved, so that all RA2 in all chains can test the shared triggers (r27928) +- Fix: [NewGRF] Industry random triggers are stored per tile, even when randomising the shared random bits of the parent industry (r27928) +- Fix: [NPF] Reserved track bits were not accounted for when trying to find any safe position (r27912) +- Fix: Do not modify argv[0] [FS#6575] (r27886) +- Fix: Do not search directories when opening ini files as we already have their full path [FS#6421] (r27816) +- Fix: Road tunnel/bridge heads have no trackbits wrt. catenary drawing (r27812) + + +1.7.2 (2017-12-24) +------------------------------------------------------------------------ +(None) + + +1.7.2-RC1 (2017-12-11) +------------------------------------------------------------------------ +- Change: When train depots have a horizontal scrollbar, allow scrolling 1 tile beyond the longest train, so you can actually attach a wagon at the end (r27937) +- Fix: When moving wagons in the depot, the drag highlight did not exactly match the length of the dragged wagon chain (r27936) +- Fix: [Win32] Right mouse scrolling didn't work properly with the Windows 10 Fall Creators Update [FS#6629] (r27935) +- Fix: Forest, candyfloss forest and battery farm skipped the first animation frame [FS#6639] (r27932) +- Fix: Glyphs in range U+0020 to U+00FF may only be defined in orig_extra.grf, not in openttd.grf [FS#6620] (r27915) +- Fix: 'unban' console command was not handling IPv6 adresses properly (r27914, r27913) +- Fix: Keep the 'link' between industry chain and smallmap windows whenever possible [FS#6585] (r27905) +- Fix: When the last vehicle is removed from a shared orders group, hide the 'Stop sharing' button in the vehicle orders window [FS#6593] (r27904) +- Fix: Tooltip of 'increase service interval' said 'decrease' [FS#6606] (r27895) +- Fix: Console command parser passed invalid strings to the debug output, if command lines had many parameters [FS#6576] (r27884, r27883) + + +1.7.1 (2017-06-13) +------------------------------------------------------------------------ +(None) + + +1.7.1-RC1 (2017-05-04) +------------------------------------------------------------------------ +- Fix: Add missing game script event for ships arriving at a station [FS#6560] (r27859, r27858) +- Fix: StringID truncation to 16 bits broke string remapping test [FS#6555] (r27851) +- Fix: Infinite loop in pathfinder when checking safe waiting position from a waypoint [FS#5926] (r27846) +- Fix: [YAPF] Consider depot as destination before reversing path and applying penalty (r27843) +- Fix: Don't consider locks or ship depots as clear water when placing industries (r27841) +- Fix: Small news window's fake caption was not sized to fit its text (r27838) +- Fix: Black remap did nothing in 8bpp-simple blitter (r27837) +- Fix: Misaligned resize icon due to widget bounds being inclusive (r27831) +- Fix: Update viewport sign dimensions when changing GUI zoom level (r27827, r27819) +- Fix: Vehicle viewport is not user scrollable so flag window as such (r27823) +- Fix: Allow dropdown to be drawn above origin widget even with scrollbar (r27820) +- Fix: 32bpp-anim blitters assumed that pitch and width of the screen were equal [FS#6545] (r27796) +- Fix: Chat text background overflowed due to missing padding [FS#6526] (r27794) +- Fix: Failed to load lzo compressed savegames sometimes [FS#6450] (r27793) +- Fix: [Win32] Mark OpenTTD as DPI-aware to avoid OS window scaling that breaks mouse input [FS#6366] (r27791, r27790) +- Fix: [NewGRF] Get vehicle load amount after executing new cargo trigger [FS#6536] (r27788) +- Fix: AI configuration changed incorrect parameter when some parameters are hidden [FS#6479] (r27787, r27786) +- Fix: Buoys not always drawn after being placed depending on zoom level [FS#6508] (r27785) +- Fix: Allow rail conversion even if ship is on tile [FS#6505] (r27784) + + +1.7.0 (2017-04-01) +------------------------------------------------------------------------ +(None) + + +1.7.0-RC1 (2017-03-11) +------------------------------------------------------------------------ +- Feature: [NewGRF] Extend the DCxx range to D800-DFFF (r27769) +- Feature: [NewGRF, script] Increase the maximum number of GameScript texts to 64k, and NewGRF texts to 512k (r27758) +- Feature: [NewGRF] CB 37 results 0x0401 and 0x0800-0BFF for improved control of display of input cargos in the industry GUI (r27751) +- Feature: Sprites missing in outdated basesets are now provided by openttd.grf (r27732, r27731, r27730) +- Feature: [NewGRF] String command 9A 1E to print the name of a cargo type (r27707, r27706) +- Feature: [Debug] Assign descriptive names to threads [FS#6471] (r27674, r27673, r27670) +- Feature: [NewGRF] Allow composing vehicles from multiple sprites (r27668) +- Change: Enable realistic train and road vehicle acceleration by default (r27760) +- Change: Hide the drive-in stops from the tram station picker (r27734) +- Change: Do not count static NewGRF when checking for the maximum number of NewGRFs in a game (r27729) +- Change: Limit waypoint area by maximum station spread during dragging (r27710) +- Change: [Build] Re-enable Wnarrowing for gcc 4.9+ [FS#6532] (r27709, r27703) +- Change: List railtype of rail tiles explicitly in the tile info window (r27686) +- Change: Re-arrange the autoreplace GUI for trains, and do not filter it by railtype by default (r27683) +- Change: Various performance improvements to CargoDist and LinkGraphs (r27682, r27681, r27614, r27613, r27612, r27611) +- Change: Improve randomisation of rough land appearance (r27657) +- Change: [Build] Enable C++11 for clang 3.3 (r27654) +- Fix: Insufficient thread synchronisation when switching blitters lead to crashes [FS#6510] (r27775) +- Fix: Enabling palette animation for 32bpp blitters while paused skipped initialisation of the palette and resulted in black windows [FS#5889] (r27774) +- Fix: Intro games other than the traditional nightly one would cause townname NewGRFs to not get activated in the game options [FS#5819] (r27772) +- Fix: Some variables were not reset between loading old savegames, which made loading them fail [FS#6540] (r27770) +- Fix: Removing secondary roadtypes from bridges was factor 2 too cheap [FS#6538] (r27746) +- Fix: Extra viewports did not center on the selected tile [FS#6537] (r27743) +- Fix: [Build] Building on newer OSX versions with newer SDKs [FS#6295, FS#6502] (r27727, r27675) +- Fix: Improve error message when trying to build rail track over a depot (r27726) +- Fix: Rescanning NewGRF in-game could break the loaded NewGRF, if very many NewGRF were in use (r27721) +- Fix: Text could overflow various GUI elements [FS#6527] (r27713) +- Fix: Memory leak when reloading NewGRF (r27690, r27688, r27687) +- Fix: When removing objects of bankrupt companies the tiles may revert to canal. In that case also check the ownership of the canal [FS#6511] (r27656) +- Fix: Make the console file commands operate independent of the save/load GUI (r27645) +- Fix: When dragging vehicles in group or depot GUI, draw the complete articulated vehicle (r27632) +- Fix: When dragging multiple vehicles in the depot, make the destination gap as long as the chain instead of just considering the first vehicle (r27629) +- Fix: [Build] Change the GCC version detection so that it works with two-digit and truncated versions [FS#6487] (r27623, r27616) +- Fix: Do not hide filtered and highlighted industries by overlapping tiles in the zoomed-out smallmap (r27622, r27621, r27620) +- Fix: [Script] Kill scripts, when a non-suspendable valuator call takes way too long [FS#6473] (r27594) + + +1.6.1 (2016-07-01) +------------------------------------------------------------------------ +- Fix: Compilation and optimisation issues with GCC6 (r27606, r27605, r27595) +- Fix: Compilation with --disable-network [FS#6481] (r27602) +- Fix: [NewGRF] shift-and-add-divide/modulo varadjusts use signed division/modulo (r27600) +- Fix: Company 0 could accept engine previews before they were offered (r27598) + + +1.6.1-RC1 (2016-06-01) +------------------------------------------------------------------------ +- Feature: Mexican Spanish (r27564, r27553, r27552) +- Change: Performance improvement for dedicated servers by skipping drawing calls earlier in the process [FS#6402] (r27579) +- Fix: Automatic servicing of road vehicles compared path finder costs with tile distances, thus vehicles went to depots which were factor 100 too far away [FS#6410] (r27586) +- Fix: Enforce a non-zero load amount for all vehicles, so that vehicles can process their cargo reservations [FS#6437] (r27585, r27584) +- Fix: Do not decrease the column width of depot windows when vehicles with high unitnumbers leave [FS#6415] (r27583) +- Fix: Button size computation in script configuration window [FS#6461] (r27581) +- Fix: [NewGRF] Set date of last service on construction also for wagons and articulated parts [FS#6395] (r27580) +- Fix: Vehicles could not be hidden from the purchase list when they were in exclusive preview [FS#6454] (r27578) +- Fix: Dock and roadstop picker, client list and town authority window did not auto-resize according to their content when they were positioned at the bottom of the screen [FS#6386] (r27577) +- Fix: Various incorrect but uncritical size computations in the content client [FS#6449] (r27576, r27570) +- Fix: Memory leak when disabling palette animation [FS#6404] (r27575) +- Fix: [NewGRF] The house id as returned by house variable 66 was incorrect when querying neighboured tiles [FS#6432] (r27574) +- Fix: [Build] Compilation failure with gcc 6.1 due to headers included after safeguards.h [FS#6467] (r27573) +- Fix: Convenience savegame bump to distinguish 1.6 savegames from 1.5 savegames [FS#6442] (r27572) +- Fix: [Build] Force sorting to be locale independent, so files are always ordered the same and by that token better diff-able (r27562, r27558) +- Fix: Typos in comments and string (r27561, r27560) +- Fix: [Build] bashism that caused different CFLAGS with bash vs dash (r27557) +- Fix: Use a more appropiate sound effect for convert-rail (r27547) +- Fix: Remove SetFill from vehicle GUI buttons, so that the viewport is resized instead of them in case of long window titles (r27546) +- Fix: [Script] Generation of API wrappers (r27545, r27544, r27543) +- Fix: [Windows] ICU got disabled for Windows builds, breaking RTL support [FS#6427] (r27542) +- Fix: [NewGRF] Station spritelayouts did not accept the var10 flag for the palette [FS#6435] (r27534) + + +1.6.0 (2016-04-01) +------------------------------------------------------------------------ +(None) + + +1.6.0-RC1 (2016-03-01) +------------------------------------------------------------------------ +- Feature: [NewGRF] Allow custom sound IDs in RV property 0x12, ship property 0x10 and aircraft property 0x12 (r27507) +- Feature: When viewing online content of a particular type, hide content of other types unless they have been (auto)selected for download (r27469, r27468, r27444) +- Feature: [NewGRF] Move sprite 8 positions in sprite aligner with ctrl+click [FS#6241] (r27451) +- Feature: Lower the sell-vehicle and sell-chain buttons in the train depot GUI while dragging a vehicle over it [FS#6391] (r27450, r27446) +- Feature: Make the object placement GUI an independent window (r27438, r27397, r27346) +- Feature: [Build] Project files and compilation with MSVC2015 (r27385, r27382, r27381, r27380, r27379) +- Feature: [NewGRF] Allow railtype NewGRF to define separate sprites for the fences on either track side [FS#6315] (r27354, r27343) +- Feature: [NewGRF] Increase the maximum amount of industry types to 128 per NewGRF and 240 in total (r27279) +- Feature: Make Ctrl+Remove-Roadstop also remove the road, just like for rail stations [FS#6252] (r27251) +- Change: [NewGRF] Allow static NewGRF to enable the second rocky tile set (r27497) +- Change: Round loading percentage in loading indicators and conditional orders towards 50%, so that 0% and 100% mean completely empty or full (r27426) +- Change: [Build] Rework the configure system to make more use of pkg-config (r27377:r27366, r27361, r27360) +- Change: Enable YAPF cache debugging with desync debug level 2 (r27332) +- Change: [strgen] Default plural subparameter position for CARGO_xxx string control codes is subparameter 1 (r27295) +- Change: [NewGRF] Translate industry variable A6 (r27267) +- Change: Do not consider cargo that is already being loaded as waiting cargo wrt. the station rating [FS#6165] (r27256) +- Change: Tune down terrain generation to reduce amount of long slopes (r27230) +- Change: Generate more detailed curves at the coast (r27229) +- Change: Slightly more water in the non-custom sea levels (r27228) +- Change: Be more lenient about road stop removal when at least one stop could be removed [FS#6262] (r27225) +- Fix: [Win32] Stdin/out/err need to be re-assigned differently if the runtime lib of MSVC2015 is used (r27481) +- Fix: [Haiku] On Haiku use the appropriate system variable to obtain the include dir [FS#6401] (r27472) + + +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.lib b/config.lib new file mode 100644 index 0000000000..2bcc643fba --- /dev/null +++ b/config.lib @@ -0,0 +1,3619 @@ +# $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" + pkg_config="pkg-config" + os="DETECT" + 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_xaudio2="1" + with_sort="1" + with_iconv="1" + with_midi="" + with_midi_arg="" + with_libtimidity="1" + with_fluidsynth="1" + with_freetype="1" + with_fontconfig="1" + with_icu_layout="1" + with_icu_sort="1" + static_icu="0" + with_uniscribe="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 + pkg_config + os + 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_xaudio2 + with_sort + with_iconv + with_midi + with_midi_arg + with_libtimidity + with_fluidsynth + with_freetype + with_fontconfig + with_icu_layout + with_icu_sort + static_icu + with_uniscribe + with_threads + with_distcc + with_ccache + with_grfcodec + with_nforenum + with_sse + CC CXX CFLAGS CXXFLAGS LDFLAGS CFLAGS_BUILD CXXFLAGS_BUILD LDFLAGS_BUILD PKG_CONFIG_PATH PKG_CONFIG_LIBDIR" +} + +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";; + --pkg-config) prev_p="pkg_config";; + --pkg-config=*) pkg_config="$optarg";; + --strip) prev_p="strip";; + --strip=*) strip="$optarg";; + --lipo) prev_p="lipo";; + --lipo=*) lipo="$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-fluidsynth) with_fluidsynth="2";; + --without-fluidsynth) with_fluidsynth="0";; + --with-fluidsynth=*) with_fluidsynth="$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_layout="2";with_icu_sort="2";; + --without-icu) with_icu_layout="0";with_icu_sort="0";; + --with-icu=*) with_icu_layout="$optarg";with_icu_sort="$optarg";; + --with-libicu) with_icu_layout="2";with_icu_sort="2";; + --without-libicu) with_icu_layout="0";with_icu_sort="0";; + --with-libicu=*) with_icu_layout="$optarg";with_icu_sort="$optarg";; + --with-icu-layout) with_icu_layout="2";; + --without-icu-layout) with_icu_layout="0";; + --with-icu-layout=*) with_icu_layout="$optarg";; + --with-icu-sort) with_icu_sort="2";; + --without-icu-sort) with_icu_sort="0";; + --with-icu-sort=*) with_icu_sort="$optarg";; + --static-icu) static_icu="1";; + --static-icu=*) static_icu="$optarg";; + --static-libicu) static_icu="1";; + --static-libicu=*) static_icu="$optarg";; + + --with-uniscribe) with_uniscribe="2";; + --without-uniscribe) with_uniscribe="0";; + --with-uniscribe=*) with_uniscribe="$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-xaudio2) with_xaudio2="2";; + --without-xaudio2) with_xaudio2="0";; + --with-xaudio2=*) with_xaudio2="$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";; + PKG_CONFIG_PATH=* | --PKG_CONFIG_PATH=* | --PKG-CONFIG-PATH=*) PKG_CONFIG_PATH="$optarg";; + PKG_CONFIG_LIBDIR=* | --PKG_CONFIG_LIBDIR=* | --PKG-CONFIG-LIBDIR=*) PKG_CONFIG_LIBDIR="$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 +} + +# Export a variable so tools like pkg-config can see it when invoked. +# If the variable contains an empty string then unset it. +# $1 - name of the variable to export or unset +export_or_unset() { + eval local value=\$$1 + if [ -n "$value" ]; then + export $1; + log 2 "using $1=$value"; + else + unset $1; + log 2 "not using $1"; + fi +} + +check_params() { + # Some params want to be in full uppercase, else they might not work as + # expected.. fix that here + + os=`echo $os | tr '[a-z]' '[A-Z]'` + cpu_type=`echo $cpu_type | tr '[a-z]' '[A-Z]'` + + # Export some variables to be used by pkg-config + # + # PKG_CONFIG_LIBDIR variable musn't be set if we are not willing to + # override the default pkg-config search path, it musn't be an empty + # string. If the variable is empty (e.g. when an empty string comes + # from config.cache) then unset it. This way the "don't override" state + # will be properly preserved when (re)configuring. + export_or_unset PKG_CONFIG_PATH + export_or_unset PKG_CONFIG_LIBDIR + + # Check if all params have valid values + + # OS only allows DETECT, UNIX, OSX, FREEBSD, DRAGONFLY, OPENBSD, NETBSD, MORPHOS, BEOS, HAIKU, SUNOS, CYGWIN, MINGW, OS2, and DOS + if [ -z "`echo $os | egrep '^(DETECT|UNIX|OSX|FREEBSD|DRAGONFLY|OPENBSD|NETBSD|HPUX|MORPHOS|BEOS|HAIKU|SUNOS|CYGWIN|MINGW|OS2|DOS)$'`" ]; 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]" + 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" ]; 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" ]; 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_config" ]; 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 + + if [ "$with_uniscribe" != "0" ]; then + if [ "$os" != "MINGW" ]; then + if [ "$with_uniscribe" != "1" ]; then + log 1 "configure: error: Uniscribe is only supported on native Win32 targets" + exit 1 + fi + with_uniscribe="0" + + log 1 "checking Uniscribe text layout... not Windows, skipping" + else + log 1 "checking Uniscribe text layout... found" + + # Don't use ICU unless forced. + if [ "$with_icu_layout" = "1" ]; then + with_icu_layout="0" + fi + if [ "$with_icu_sort" = "1" ]; then + with_icu_sort="0" + fi + fi + fi + + detect_xdg_basedir + detect_png + detect_freetype + detect_fontconfig + detect_icu_layout + detect_icu_sort + detect_libtimidity + detect_fluidsynth + + 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 + + if [ "$with_xaudio2" != "0" ]; then + if [ "$os" != "MINGW" ] && [ "$os" != "CYGWIN" ]; then + if [ "$with_xaudio2" != "1" ]; then + log 1 "configure: error: xaudio2 is only supported on Win32 targets" + exit 1 + fi + with_xaudio2="0" + + log 1 "checking xaudio2... not Windows, skipping" + else + check_xaudio2 + fi + fi + + detect_sort + + # 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" = "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 + + # Get the compiler to tell us who it is + version_line="`$1 --version | head -n1`" + + eval eval "flags=\\\$$2" + eval eval "cxxflags=\\\$$3" + eval eval "ldflags=\\\$$4" + eval eval "features=\\\$$5" + + if [ `echo "$version_line" | cut -d' ' -f1` = "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" + 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 echo "$version_line" | grep -q "clang"; then + # Enable some things only for certain clang versions + # Need to try really hard to get the version line, because OSX clang likes to hide its true version + cc_version="`$1 -v 2>&1 | grep -i version | 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 -Wextra" + + # 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" + + # Assume gcc, since it just uses argv[0] in its --version output + else + # Enable some things only for certain GCC versions + # cc_version = major_version * 100 + minor_version + # For example: "3.3" -> 303, "4.9.2" -> 409, "6" -> 600, "23.5" -> 2305 + cc_version=`$1 -dumpversion | $awk -F . '{printf "%d%02d", $1, $2}'` + + if [ $cc_version -lt 303 ]; 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 406 ]; 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 304 ]; then + # Warn when a variable is used to initialise itself: + # int a = a; + flags="$flags -Winit-self" + fi + + if [ $cc_version -ge 400 ]; 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 402 ]; 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 -eq 405 ]; 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 -eq 407 ]; 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" + fi + + if [ $cc_version -ge 407 ]; then + # Disable bogus 'attempt to free a non-heap object' warning + flags="$flags -Wno-free-nonheap-object" + fi + + if [ $cc_version -ge 600 ]; then + # -flifetime-dse=2 (default since GCC 6) doesn't play + # well with our custom pool item allocator + cxxflags="$cxxflags -flifetime-dse=1" + 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 406 ]; 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_ENV="$CFLAGS_BUILD" + CFLAGS_BUILD="" + # Special CXXFlags for BUILD + CXXFLAGS_BUILD_ENV="$CXXFLAGS_BUILD" + CXXFLAGS_BUILD="" + # LDFLAGS for BUILD + LDFLAGS_BUILD_ENV="$LDFLAGS_BUILD" + LDFLAGS_BUILD="" + # FEATURES for BUILD (lto) + FEATURES_BUILD="" + # General CFlags for HOST + CFLAGS_ENV="$CFLAGS" + CFLAGS="" + # Special CXXFlags for HOST + CXXFLAGS_ENV="$CXXFLAGS" + CXXFLAGS="" + # Libs to compile. In fact this is just LDFLAGS + LIBS="" + # LDFLAGS used for HOST + LDFLAGS_ENV="$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" + CXXFLAGS="$CXXFLAGS -std=c++11" + CXXFLAGS_BUILD="$CXXFLAGS_BUILD -std=c++11" + + 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" + 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" 2>/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" 2>/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 400 ]; 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 406 ]; 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 404 ]; then + LDFLAGS_BUILD="$LDFLAGS_BUILD -static-libgcc -static-libstdc++" + fi + if [ $cc_version -ge 407 ]; 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" != "OS2" ]; then + LIBS="$LIBS -lpthread" + fi + + if [ "$os" != "CYGWIN" ] && [ "$os" != "HAIKU" ] && [ "$os" != "MINGW" ] && [ "$os" != "DOS" ]; then + LIBS="$LIBS -lc" + 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 + 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" ]; then + CFLAGS="$CFLAGS -DWIN" + fi + + if [ -n "$allegro_config" ]; then + CFLAGS="$CFLAGS -DWITH_ALLEGRO" + CFLAGS="$CFLAGS `$allegro_config --cflags`" + if [ "$os" != "MINGW" ] && [ "$os" != "CYGWIN" ]; 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 [ "$enable_static" != "0" ]; then + LIBS="$LIBS `$sdl_config --static --libs`" + else + LIBS="$LIBS `$sdl_config --libs`" + 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 + CFLAGS="$CFLAGS -DWITH_ZLIB" + CFLAGS="$CFLAGS `$zlib_config --cflags | tr '\n\r' ' '`" + if [ "$enable_static" != "0" ]; then + LIBS="$LIBS `$zlib_config --libs --static | tr '\n\r' ' '`" + else + LIBS="$LIBS `$zlib_config --libs | tr '\n\r' ' '`" + fi + 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 + LIBS="$LIBS `$png_config --libs --static | tr '\n\r' ' '`" + 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 + LIBS="$LIBS `$fontconfig_config --libs --static | tr '\n\r' ' '`" + 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 + LIBS="$LIBS `$freetype_config --libs --static | tr '\n\r' ' '` -lfreetype" + else + LIBS="$LIBS `$freetype_config --libs | tr '\n\r' ' '`" + fi + fi + + if [ -n "$icu_layout_config" ]; then + CFLAGS="$CFLAGS -DWITH_ICU_LAYOUT" + CFLAGS="$CFLAGS `$icu_layout_config --cflags | tr '\n\r' ' '`" + + if [ "$static_icu" != "0" ]; then + LIBS="$LIBS `$icu_layout_config --libs --static | tr '\n\r' ' ' | sed s/-licu/-lsicu/g`" + else + LIBS="$LIBS `$icu_layout_config --libs | tr '\n\r' ' '`" + fi + fi + + if [ -n "$icu_sort_config" ]; then + CFLAGS="$CFLAGS -DWITH_ICU_SORT" + CFLAGS="$CFLAGS `$icu_sort_config --cflags | tr '\n\r' ' '`" + + if [ "$static_icu" != "0" ]; then + LIBS="$LIBS `$icu_sort_config --libs --static | tr '\n\r' ' ' | sed s/-licu/-lsicu/g`" + else + LIBS="$LIBS `$icu_sort_config --libs | tr '\n\r' ' '`" + fi + fi + + if [ "$with_uniscribe" != "0" ]; then + CFLAGS="$CFLAGS -DWITH_UNISCRIBE" + LIBS="$LIBS -lusp10" + 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 400 ]; then + CFLAGS="$CFLAGS -Wno-non-virtual-dtor" + fi + fi + + if [ "$with_xaudio2" != "0" ]; then + CFLAGS="$CFLAGS -DWITH_XAUDIO2" + fi + + if [ -n "$libtimidity_config" ]; then + CFLAGS="$CFLAGS -DLIBTIMIDITY" + CFLAGS="$CFLAGS `$libtimidity_config --cflags | tr '\n\r' ' '`" + + if [ "$enable_static" != "0" ]; then + LIBS="$LIBS `$libtimidity_config --libs --static | tr '\n\r' ' '`" + else + LIBS="$LIBS `$libtimidity_config --libs | tr '\n\r' ' '`" + fi + fi + + if [ -n "$fluidsynth" ]; then + LIBS="$LIBS -lfluidsynth" + CFLAGS="$CFLAGS -DFLUIDSYNTH" + 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 + + # All flags to be extended via the env + CFLAGS_BUILD="$CFLAGS_BUILD $CFLAGS_BUILD_ENV" + CXXFLAGS_BUILD="$CXXFLAGS_BUILD $CXXFLAGS_BUILD_ENV" + LDFLAGS_BUILD="$LDFLAGS_BUILD $LDFLAGS_BUILD_ENV" + CFLAGS="$CFLAGS $CFLAGS_ENV" + CXXFLAGS="$CXXFLAGS $CXXFLAGS_ENV" + LDFLAGS="$LDFLAGS $LDFLAGS_ENV" + + 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;s@[ ]*-[^D][^ ]*@@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 "$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 + elif [ -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 + if [ -z "$5" ]; then + log 1 "checking $1... $compiler not found" + log 1 "I couldn't detect any $6 binary for $3" + exit 1 + else + compiler="$3-$5" + 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 $5 binary for $3" + exit 1 + fi + 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 + 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() { + check_compiler "build system type" "cc_build" "$build" "$cc_build" "$CC" "gcc" "cc" "0" "-dumpmachine" +} + +check_host() { + # By default the host is the build + if [ -z "$host" ]; then host="$build"; fi + check_compiler "host system type" "cc_host" "$host" "$cc_host" "$CC" "gcc" "cc" "0" "-dumpmachine" +} + +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" ]; 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 + 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_xaudio2() { + echo " + #include + + #undef NTDDI_VERSION + #undef _WIN32_WINNT + + #define NTDDI_VERSION NTDDI_WIN8 + #define _WIN32_WINNT _WIN32_WINNT_WIN8 + + #include + int main(int argc, char *argv[]) { }" > xaudio2.test.c + $cxx_host $CFLAGS xaudio2.test.c -o xaudio2.test 2> /dev/null + res=$? + rm -f xaudio2.test.c xaudio2.test + + if [ "$res" != "0" ]; then + if [ "$with_xaudio2" != "1" ]; then + log 1 "configure: error: xaudio2 is not available on this system" + exit 1 + fi + with_xaudio2="0" + + log 1 "checking xaudio2... not found" + else + log 1 "checking xaudio2... 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, and DOS + + # 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} + '` + + 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, and DOS" + 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 Allegro. 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 + + detect_pkg_config "$with_allegro" "allegro" "allegro_config" "4.4" +} + + +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 + + detect_pkg_config "$with_sdl" "sdl" "sdl_config" "1.2" +} + +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 /mingw$cpu_type/include/$4*.h 2>/dev/null | egrep \"\/$5\$\"`" + fi + eval "res=\$$2" + if [ -z "$res" ]; then + log 2 " trying /mingw$cpu_type/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 + if [ -z "$includeDir" ]; then + includeDir=`finddir B_SYSTEM_HEADERS_DIRECTORY` + fi + eval "$2=`ls -1 $includeDir/$4*.h 2>/dev/null | egrep \"\/$5\$\"`" + eval "res=\$$2" + if [ -z "$res" ]; then + log 2 " trying $includeDir/$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" + eval "$2=`ls /mingw$cpu_type/lib/*.a 2>/dev/null | egrep \"\/$3\$\"`" + fi + eval "res=\$$2" + if [ -z "$res" ]; then + log 2 " trying /mingw$cpu_type/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_pkg_config "$with_zlib" "zlib" "zlib_config" "1.2" +} + +detect_lzo2() { + detect_library "$with_lzo2" "lzo2" "liblzo2.a" "lzo/" "lzo1x.h" +} + +detect_libtimidity() { + detect_pkg_config "$with_libtimidity" "libtimidity" "libtimidity_config" "0.1" "1" +} + +detect_fluidsynth() { + detect_library "$with_fluidsynth" "fluidsynth" "" "" "fluidsynth.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') + # $5 - check for dedicated, 1 is "skif if dedicated" + + # 0 means no, 1 is auto-detect, 2 is force + if [ "$1" = "0" ]; then + log 1 "checking $2... disabled" + + eval "$3=\"\"" + return 0 + fi + + if [ "$5" = "1" ] && [ "$1" = "1" ] && [ "$enable_dedicated" != "0" ]; then + log 1 "checking $2... dedicated server, skipping" + + 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() { + detect_pkg_config "$with_png" "libpng" "png_config" "1.2" +} + +detect_freetype() { + detect_pkg_config "$with_freetype" "freetype2" "freetype_config" "2.2" "1" +} + +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 [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ]; 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" "1" +} + +detect_icu_layout() { + if [ "$with_cocoa" != "0" ] && [ "$with_icu_layout" = "1" ]; then + log 1 "checking icu-lx... OSX, skipping" + icu_layout_config="" + return 0 + fi + + detect_pkg_config "$with_icu_layout" "icu-lx" "icu_layout_config" "4.8" "1" +} + +detect_icu_sort() { + if [ "$with_cocoa" != "0" ] && [ "$with_icu_sort" = "1" ]; then + log 1 "checking icu-i18n... OSX, skipping" + icu_sort_config="" + return 0 + fi + + detect_pkg_config "$with_icu_sort" "icu-i18n" "icu_sort_config" "4.8" "1" +} + +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 + # Iterate over search paths + iconv="" + search_paths=`LC_ALL=C $cxx_host $OSX_SYSROOT $CFLAGS -E - -v &1 | \ + $awk '/#include <...> search starts here:/{flag=1;next}/End of search list./{flag=0}flag'` + for path in $search_paths; do + iconv=`ls -1 $path 2>/dev/null | grep "iconv.h"` + if [ -n "$iconv" ]; then + break + fi + done + 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@!!DEPEND!!@$DEPEND@g; + s@!!SETTINGSGEN!!@$SETTINGSGEN@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_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 " --pkg-config=PKG-CONFIG the pkg-config to use in configure [pkg-config]" + 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/HAIKU" + 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[=\"pkg-config libtimidity\"]" + echo " enables libtimidity support" + echo " --with-fluidsynth enables fluidsynth support" + echo " --with-allegro[=\"pkg-config allegro\"]" + echo " enables Allegro video driver support" + echo " --with-cocoa enables COCOA video driver (OSX ONLY)" + echo " --with-sdl[=\"pkg-config sdl\"] enables SDL video driver support" + echo " --with-zlib[=\"pkg-config zlib\"]" + echo " enables zlib support" + echo " --with-liblzma[=\"pkg-config liblzma\"]" + echo " enables liblzma support" + echo " --with-liblzo2[=liblzo2.a] enables liblzo2 support" + echo " --with-png[=\"pkg-config libpng\"]" + echo " enables libpng support" + echo " --with-freetype[=\"pkg-config freetype2\"]" + 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 enables icu components for layout and sorting" + echo " --with-icu-layout[=\"pkg-config icu-lx\"]" + echo " enables icu components for layouting (right-to-left support)" + echo " --with-icu-sort[=\"pkg-config icu-i18n\"]" + echo " enables icu components for locale specific string sorting" + 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 " --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 " PKG_CONFIG_PATH additional library search paths (see \"man pkg-config\")" + echo " PKG_CONFIG_LIBDIR replace the default library search path (see \"man pkg-config\")" + 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/configure b/configure new file mode 100755 index 0000000000..afc1de51b4 --- /dev/null +++ b/configure @@ -0,0 +1,173 @@ +#!/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" ]; then + EXE=".exe" +fi + +TTD="openttd$EXE" +STRGEN="strgen$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 == "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 == "MSVC" && "'$os'" != "MSVC") { next; } + if ($0 == "DIRECTMUSIC" && "'$with_direct_music'" == "0") { next; } + if ($0 == "LIBTIMIDITY" && "'$libtimidity'" == "" ) { next; } + if ($0 == "FLUIDSYNTH" && "'$fluidsynth'" == "" ) { 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\" | LC_ALL=C $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 0000000000..547854e508 --- /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 (git repository), 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 git 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 0000000000..84fa6ec7e1 --- /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.md b/docs/Readme_Windows_MSVC.md new file mode 100644 index 0000000000..90ab2af657 --- /dev/null +++ b/docs/Readme_Windows_MSVC.md @@ -0,0 +1,71 @@ +# Compiling OpenTTD using Microsoft Visual C++ + +Last updated: 2018-12-27 + +## Supported MSVC compilers + +OpenTTD includes projects for Visual Studio 2015 Update 3 or more recent. +You can download the free Visual Studio Community Edition from Microsoft at +https://visualstudio.microsoft.com/vs/community/. + +## Required files + +### Microsoft platform files + +OpenTTD needs the Platform SDK, if it isn't installed already. This can be +done during installing Visual Studio, by selecting +`Visual C++ MFC for x86 and x64` (and possibly +`Visual C++ ATL for x86 and x64` depending on your version). If not, you +can get it at this location: + +- [MS Windows Platform SDK](https://developer.microsoft.com/en-US/windows/downloads/windows-10-sdk) + +Install the SDK by following the instructions as given. + +### OpenTTD dependencies + +Dependencies for OpenTTD on Windows are handled via +[vcpkg](https://github.com/Microsoft/vcpkg/). First you need to install vcpkg +by following the `Quick Start` intructions of their +[README](https://github.com/Microsoft/vcpkg/blob/master/README.md). + +After this, you can install the dependencies OpenTTD needs. We advise to use +the `static` versions, and OpenTTD currently needs the following dependencies: + +- freetype +- liblzma +- libpng +- lzo +- zlib + +To install both the x64 (64bit) and x86 (32bit) variants, you can use: + +```ps +.\vcpkg install freetype:x64-windows-static liblzma:x64-windows-static libpng:x64-windows-static lzo:x64-windows-static zlib:x64-windows-static +.\vcpkg install freetype:x86-windows-static liblzma:x86-windows-static libpng:x86-windows-static lzo:x86-windows-static zlib:x86-windows-static +``` + +## TTD Graphics files + +See section 4.1 of README.md for the required 3rdparty files and how to install them. + +## Compiling + +Open the appropriate `sln` (Solution) file for your version of Visual Studio: + +- VS 2015: projects/openttd_vs140.sln +- VS 2017: projects/openttd_vs141.sln +- VS 2019: projects/openttd_vs142.sln + +Set the build mode to `Release` in +`Build > Configuration manager > Active solution configuration`. +You can now compile. + +If everything works well the binary should be in `objs\Win[32|64]\Release\openttd.exe` +and in `bin\openttd.exe` + +## Problems + +If compilation fails, double-check that you are using the latest github +source. If it still doesn't work, check in on IRC (irc://irc.oftc.net/openttd), +to ask for help. diff --git a/docs/admin_network.txt b/docs/admin_network.txt new file mode 100644 index 0000000000..904f3ca204 --- /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 0000000000..b0b6bd7d47 --- /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 0000000000..39098a388b --- /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 0000000000000000000000000000000000000000..bcbcea530848cd14938aec3196e298c133dfd3d6 GIT binary patch literal 47024 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 E0Mf(@r2qf` literal 0 HcmV?d00001 diff --git a/docs/elrail_track.png b/docs/elrail_track.png new file mode 100644 index 0000000000000000000000000000000000000000..a27276b30dfcc4f530b8e6947a829d435a9eabb3 GIT binary patch literal 47122 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